summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/contentcapture/Android.bp9
-rw-r--r--apct-tests/perftests/inputmethod/Android.bp9
-rw-r--r--apex/appsearch/Android.bp10
-rw-r--r--apex/appsearch/framework/Android.bp9
-rw-r--r--apex/appsearch/framework/api/current.txt4
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java53
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java85
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java99
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java3
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/SearchResults.java20
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java6
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java24
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java112
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java6
-rw-r--r--apex/appsearch/service/Android.bp9
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java29
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java49
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java43
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchMigrationHelperImpl.java2
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java200
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java122
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java219
-rw-r--r--apex/appsearch/synced_jetpack_changeid.txt2
-rw-r--r--apex/appsearch/testing/Android.bp9
-rw-r--r--apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java110
-rw-r--r--apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java6
-rw-r--r--apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java22
-rw-r--r--apex/jobscheduler/framework/java/android/app/AlarmManager.java4
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java43
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java4
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java4
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java136
-rw-r--r--apex/jobscheduler/service/jni/Android.bp9
-rw-r--r--apex/media/service/Android.bp10
-rw-r--r--cmds/abx/Android.bp17
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java5
-rw-r--r--cmds/hid/OWNERS1
-rw-r--r--cmds/hid/jni/com_android_commands_hid_Device.cpp15
-rw-r--r--cmds/hid/jni/com_android_commands_hid_Device.h1
-rw-r--r--cmds/hid/src/com/android/commands/hid/Device.java21
-rw-r--r--cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java2
-rw-r--r--cmds/uinput/Android.bp19
-rw-r--r--cmds/uinput/jni/Android.bp9
-rw-r--r--core/api/current.txt160
-rw-r--r--core/api/module-lib-current.txt6
-rw-r--r--core/api/system-current.txt118
-rw-r--r--core/api/test-current.txt36
-rw-r--r--core/java/android/app/ActivityManager.aidl1
-rw-r--r--core/java/android/app/ActivityManager.java199
-rw-r--r--core/java/android/app/AppOpsManager.java4
-rw-r--r--core/java/android/app/BackgroundServiceStartNotAllowedException.java62
-rw-r--r--core/java/android/app/ContextImpl.java2
-rw-r--r--core/java/android/app/ForegroundServiceStartNotAllowedException.java62
-rw-r--r--core/java/android/app/IActivityManager.aidl9
-rw-r--r--core/java/android/app/ITaskStackListener.aidl4
-rw-r--r--core/java/android/app/Notification.java88
-rw-r--r--core/java/android/app/PendingIntent.java96
-rw-r--r--core/java/android/app/Service.java9
-rw-r--r--core/java/android/app/ServiceStartNotAllowedException.java43
-rw-r--r--core/java/android/app/SystemServiceRegistry.java11
-rw-r--r--core/java/android/app/TaskStackListener.java4
-rw-r--r--core/java/android/app/WallpaperColors.java87
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java116
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl3
-rw-r--r--core/java/android/app/backup/BackupManager.java61
-rw-r--r--core/java/android/app/backup/FullBackup.java118
-rw-r--r--core/java/android/app/backup/IBackupManager.aidl6
-rw-r--r--core/java/android/app/people/PeopleSpaceTile.java16
-rw-r--r--core/java/android/appwidget/AppWidgetHostView.java69
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java6
-rw-r--r--core/java/android/appwidget/AppWidgetProviderInfo.java25
-rw-r--r--core/java/android/bluetooth/BluetoothA2dp.java7
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java153
-rw-r--r--core/java/android/bluetooth/BluetoothMapClient.java101
-rw-r--r--core/java/android/bluetooth/BluetoothProfile.java1
-rw-r--r--core/java/android/bluetooth/BufferConstraints.java2
-rw-r--r--core/java/android/content/ContentResolver.java53
-rw-r--r--core/java/android/content/Context.java53
-rw-r--r--core/java/android/content/IntentSender.java50
-rw-r--r--core/java/android/content/SyncRequest.java63
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java18
-rw-r--r--core/java/android/content/pm/PackageManager.java2
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackage.java2
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageImpl.java15
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageRead.java5
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageUtils.java2
-rw-r--r--core/java/android/hardware/biometrics/BiometricConstants.java6
-rw-r--r--core/java/android/hardware/biometrics/BiometricFaceConstants.java6
-rw-r--r--core/java/android/hardware/biometrics/BiometricFingerprintConstants.java6
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java7
-rw-r--r--core/java/android/hardware/camera2/CameraExtensionCharacteristics.java51
-rw-r--r--core/java/android/hardware/camera2/CameraExtensionSession.java6
-rw-r--r--core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java312
-rw-r--r--core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java34
-rw-r--r--core/java/android/hardware/display/DeviceProductInfo.java99
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java8
-rw-r--r--core/java/android/hardware/face/FaceManager.java5
-rw-r--r--core/java/android/hardware/input/IInputManager.aidl12
-rw-r--r--core/java/android/hardware/input/InputDeviceLightsManager.java139
-rw-r--r--core/java/android/hardware/input/InputManager.java98
-rw-r--r--core/java/android/hardware/input/OWNERS3
-rw-r--r--core/java/android/hardware/lights/Light.java60
-rw-r--r--core/java/android/hardware/lights/LightState.java73
-rw-r--r--core/java/android/hardware/lights/LightsManager.java142
-rw-r--r--core/java/android/hardware/lights/LightsRequest.java32
-rw-r--r--core/java/android/hardware/lights/SystemLightsManager.java181
-rw-r--r--core/java/android/inputmethodservice/IInputMethodWrapper.java7
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java52
-rw-r--r--core/java/android/net/NetworkPolicyManager.java50
-rw-r--r--core/java/android/net/NetworkStack.java42
-rw-r--r--core/java/android/net/NetworkWatchlistManager.java4
-rw-r--r--core/java/android/net/UidRange.java4
-rw-r--r--core/java/android/net/VpnService.java3
-rw-r--r--core/java/android/net/vcn/IVcnStatusCallback.aidl3
-rw-r--r--core/java/android/net/vcn/VcnManager.java228
-rw-r--r--core/java/android/net/vcn/VcnNetworkPolicyResult.aidl20
-rw-r--r--core/java/android/net/vcn/VcnNetworkPolicyResult.java114
-rw-r--r--core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java27
-rw-r--r--core/java/android/os/BugreportManager.java30
-rw-r--r--core/java/android/os/RecoverySystem.java19
-rw-r--r--core/java/android/os/Vibrator.java3
-rw-r--r--core/java/android/os/VibratorManager.java6
-rw-r--r--core/java/android/os/incremental/IncrementalFileStorages.java9
-rw-r--r--core/java/android/os/incremental/IncrementalManager.java33
-rw-r--r--core/java/android/os/strictmode/IncorrectContextUseViolation.java2
-rw-r--r--core/java/android/provider/DeviceConfig.java8
-rw-r--r--core/java/android/provider/Settings.java47
-rw-r--r--core/java/android/provider/SimPhonebookContract.java105
-rw-r--r--core/java/android/util/FeatureFlagUtils.java4
-rw-r--r--core/java/android/util/RotationUtils.java55
-rw-r--r--core/java/android/uwb/IUwbAdapter.aidl59
-rw-r--r--core/java/android/uwb/UwbManager.java175
-rw-r--r--core/java/android/view/Display.java13
-rw-r--r--core/java/android/view/FrameMetrics.java38
-rw-r--r--core/java/android/view/IPinnedTaskListener.aidl (renamed from core/java/android/view/IPinnedStackListener.aidl)4
-rw-r--r--core/java/android/view/IWindowManager.aidl9
-rw-r--r--core/java/android/view/InputDevice.java19
-rw-r--r--core/java/android/view/SurfaceControl.java32
-rw-r--r--core/java/android/view/SurfaceControlFpsListener.java93
-rw-r--r--core/java/android/view/View.java19
-rw-r--r--core/java/android/view/ViewFrameInfo.java4
-rw-r--r--core/java/android/view/ViewRootImpl.java3
-rw-r--r--core/java/android/view/inputmethod/InputMethod.java2
-rw-r--r--core/java/android/view/inputmethod/InputMethodInfo.java51
-rw-r--r--core/java/android/widget/AbsListView.java21
-rw-r--r--core/java/android/widget/AnalogClock.java363
-rw-r--r--core/java/android/widget/HorizontalScrollView.java21
-rw-r--r--core/java/android/widget/ImageView.java1
-rw-r--r--core/java/android/widget/ProgressBar.java2
-rw-r--r--core/java/android/widget/RemoteViews.java388
-rw-r--r--core/java/android/widget/RemoteViewsListAdapter.java9
-rw-r--r--core/java/android/widget/ScrollView.java21
-rw-r--r--core/java/android/widget/TextView.java4
-rw-r--r--core/java/android/widget/ToastPresenter.java2
-rw-r--r--core/java/com/android/internal/graphics/palette/CelebiQuantizer.java50
-rw-r--r--core/java/com/android/internal/graphics/palette/CentroidProvider.java (renamed from core/java/android/uwb/AngleOfArrivalSupport.aidl)42
-rw-r--r--core/java/com/android/internal/graphics/palette/ColorCutQuantizer.java52
-rw-r--r--core/java/com/android/internal/graphics/palette/Contrast.java103
-rw-r--r--core/java/com/android/internal/graphics/palette/LABCentroid.java67
-rw-r--r--core/java/com/android/internal/graphics/palette/Mean.java45
-rw-r--r--core/java/com/android/internal/graphics/palette/MeanBucket.java42
-rw-r--r--core/java/com/android/internal/graphics/palette/Palette.java806
-rw-r--r--core/java/com/android/internal/graphics/palette/Quantizer.java11
-rw-r--r--core/java/com/android/internal/graphics/palette/Target.java465
-rw-r--r--core/java/com/android/internal/graphics/palette/VariationalKMeansQuantizer.java15
-rw-r--r--core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java269
-rw-r--r--core/java/com/android/internal/graphics/palette/WuQuantizer.java442
-rw-r--r--core/java/com/android/internal/jank/FrameTracker.java28
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java40
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java19
-rw-r--r--core/java/com/android/internal/os/Zygote.java9
-rw-r--r--core/java/com/android/internal/policy/TransitionAnimation.java28
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl2
-rw-r--r--core/java/com/android/internal/view/IInputMethod.aidl3
-rw-r--r--core/java/com/android/server/SystemConfig.java6
-rw-r--r--core/jni/Android.bp4
-rw-r--r--core/jni/AndroidRuntime.cpp4
-rw-r--r--core/jni/android_hardware_camera2_impl_CameraExtensionJpegProcessor.cpp629
-rw-r--r--core/jni/android_view_SurfaceControl.cpp52
-rw-r--r--core/jni/android_view_SurfaceControlFpsListener.cpp130
-rw-r--r--core/proto/android/server/windowmanagerservice.proto17
-rw-r--r--core/res/Android.bp67
-rw-r--r--core/res/AndroidManifest.xml10
-rw-r--r--core/res/RemoteThemeColorsAndroidManifest.xml5
-rw-r--r--core/res/remote_color_resources_res/symbols.xml4
-rw-r--r--core/res/remote_color_resources_res/values/colors.xml40
-rw-r--r--core/res/remote_color_resources_res/values/public.xml41
-rw-r--r--core/res/res/layout/notification_template_header.xml4
-rw-r--r--core/res/res/layout/notification_template_material_big_base.xml6
-rw-r--r--core/res/res/layout/notification_template_material_big_media.xml1
-rw-r--r--core/res/res/layout/notification_template_material_big_picture.xml6
-rw-r--r--core/res/res/layout/notification_template_material_big_text.xml6
-rw-r--r--core/res/res/layout/notification_template_material_media.xml3
-rw-r--r--core/res/res/values-night/values.xml2
-rw-r--r--core/res/res/values/attrs.xml98
-rw-r--r--core/res/res/values/attrs_manifest.xml5
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/dimens.xml9
-rw-r--r--core/res/res/values/public.xml9
-rw-r--r--core/res/res/values/symbols.xml3
-rw-r--r--core/res/res/values/themes_device_defaults.xml74
-rw-r--r--core/tests/GameManagerTests/Android.bp9
-rw-r--r--core/tests/batterystatstests/BatteryStatsLoadTests/Android.bp9
-rw-r--r--core/tests/batterystatstests/BatteryStatsViewer/Android.bp9
-rw-r--r--core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java227
-rw-r--r--core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java80
-rw-r--r--core/tests/coretests/src/android/util/RotationUtilsTest.java61
-rw-r--r--core/tests/coretests/src/android/view/OWNERS6
-rw-r--r--core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java46
-rw-r--r--core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java3
-rw-r--r--core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java21
-rw-r--r--core/tests/devicestatetests/Android.bp9
-rw-r--r--core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp1
-rw-r--r--core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp1
-rw-r--r--data/etc/car/com.google.android.car.networking.preferenceupdater.xml13
-rw-r--r--data/fonts/fonts.xml494
-rw-r--r--data/keyboards/OWNERS4
-rw-r--r--data/keyboards/Vendor_057e_Product_2009.kl8
-rw-r--r--graphics/java/android/graphics/FrameInfo.java18
-rw-r--r--keystore/java/android/security/IKeyChainService.aidl3
-rw-r--r--keystore/java/android/security/KeyChain.java108
-rw-r--r--keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java6
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java10
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java38
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java23
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java29
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java30
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java10
-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/splitscreen/SplitScreenController.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java27
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java148
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java56
-rw-r--r--libs/WindowManager/Shell/tests/flicker/Android.bp9
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt215
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt101
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NonRotationTestBase.kt36
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt83
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt95
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt118
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt72
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt112
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt138
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt12
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt113
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt121
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt111
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt114
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt117
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt48
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt163
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt82
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt119
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt120
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt106
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt297
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt101
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt96
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt108
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt120
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt33
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt152
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt118
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt181
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt109
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt136
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt145
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt143
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt145
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt (renamed from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransitionBase.kt)36
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt163
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp11
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt8
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt13
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt48
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java18
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java8
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java20
-rw-r--r--libs/androidfw/TEST_MAPPING4
-rw-r--r--libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp9
-rw-r--r--libs/hwui/FrameInfo.cpp8
-rw-r--r--libs/hwui/FrameInfo.h8
-rw-r--r--libs/hwui/JankTracker.cpp4
-rw-r--r--libs/hwui/SkiaCanvas.cpp62
-rw-r--r--libs/hwui/SkiaCanvas.h58
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp4
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp74
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.h19
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp4
-rw-r--r--libs/hwui/tests/unit/TypefaceTests.cpp2
-rw-r--r--location/java/android/location/ILocationManager.aidl18
-rw-r--r--location/java/android/location/LocationManager.java37
-rw-r--r--location/java/android/location/provider/ProviderRequest.java5
-rw-r--r--location/java/android/location/util/identity/CallerIdentity.java38
-rw-r--r--media/java/android/media/ImageWriter.java63
-rw-r--r--media/java/android/media/MediaPlayer.java30
-rw-r--r--media/java/android/media/session/MediaSessionManager.java104
-rw-r--r--media/jni/android_media_ImageWriter.cpp38
-rw-r--r--media/jni/android_media_JetPlayer.cpp45
-rw-r--r--media/jni/android_media_MediaCodec.cpp26
-rw-r--r--media/jni/android_media_MediaCodec.h4
-rw-r--r--media/jni/android_media_MediaCrypto.cpp8
-rw-r--r--media/jni/android_media_tv_Tuner.cpp206
-rw-r--r--media/jni/android_media_tv_Tuner.h3
-rw-r--r--media/jni/android_mtp_MtpDatabase.cpp119
-rw-r--r--media/jni/android_mtp_MtpDevice.cpp346
-rw-r--r--media/jni/android_mtp_MtpServer.cpp70
-rw-r--r--media/jni/soundpool/Android.bp13
-rw-r--r--media/jni/tuner/FrontendClient.cpp15
-rw-r--r--native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp10
-rw-r--r--native/android/tests/activitymanager/nativeTests/Android.bp9
-rw-r--r--packages/CompanionDeviceManager/AndroidManifest.xml4
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java (renamed from packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java)136
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java (renamed from packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java)117
-rw-r--r--packages/Connectivity/framework/src/android/net/CaptivePortalData.java18
-rw-r--r--packages/Connectivity/framework/src/android/net/ConnectivityManager.java73
-rw-r--r--packages/Connectivity/framework/src/android/net/IpPrefix.java8
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkCapabilities.java18
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkUtils.java41
-rw-r--r--packages/DynamicSystemInstallationService/res/values-eu/strings.xml2
-rw-r--r--packages/InputDevices/OWNERS3
-rw-r--r--packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java7
-rw-r--r--packages/SettingsLib/BannerMessagePreference/Android.bp9
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp9
-rw-r--r--packages/SettingsLib/EmergencyNumber/Android.bp9
-rw-r--r--packages/SettingsLib/FooterPreference/Android.bp9
-rw-r--r--packages/SettingsLib/MainSwitchPreference/Android.bp9
-rw-r--r--packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml1
-rw-r--r--packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java15
-rw-r--r--packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java25
-rw-r--r--packages/SettingsLib/TopIntroPreference/Android.bp9
-rw-r--r--packages/SettingsLib/UsageProgressBarPreference/Android.bp9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java3
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java20
-rw-r--r--packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java11
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java5
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java2
-rw-r--r--packages/Shell/AndroidManifest.xml2
-rw-r--r--packages/Shell/OWNERS1
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml2
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml5
-rw-r--r--packages/SystemUI/res-keyguard/values/config.xml1
-rw-r--r--packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml4
-rw-r--r--packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml4
-rw-r--r--packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml4
-rw-r--r--packages/SystemUI/res/drawable/ic_open_in_new_window.xml21
-rw-r--r--packages/SystemUI/res/drawable/ic_phone_missed.xml24
-rw-r--r--packages/SystemUI/res/drawable/people_space_content_background.xml2
-rw-r--r--packages/SystemUI/res/layout/media_output_dialog.xml3
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml12
-rw-r--r--packages/SystemUI/res/layout/tv_audio_recording_indicator.xml38
-rw-r--r--packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml (renamed from packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml)23
-rw-r--r--packages/SystemUI/res/values-television/config.xml1
-rw-r--r--packages/SystemUI/res/values-television/dimens.xml4
-rw-r--r--packages/SystemUI/res/values/attrs.xml5
-rw-r--r--packages/SystemUI/res/values/config.xml6
-rw-r--r--packages/SystemUI/res/values/config_tv.xml21
-rw-r--r--packages/SystemUI/res/values/dimens.xml2
-rw-r--r--packages/SystemUI/res/values/flags.xml2
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java223
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarOverlayController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java65
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java)281
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/CropView.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java54
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java111
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java200
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java99
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java74
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt55
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java96
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java47
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java110
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java25
-rw-r--r--packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java8
-rw-r--r--packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java5
-rw-r--r--packages/overlays/AccentColorAmethystOverlay/Android.bp9
-rw-r--r--packages/overlays/AccentColorAquamarineOverlay/Android.bp9
-rw-r--r--packages/overlays/AccentColorBlackOverlay/Android.bp9
-rw-r--r--packages/overlays/AccentColorCarbonOverlay/Android.bp9
-rw-r--r--packages/overlays/AccentColorCinnamonOverlay/Android.bp9
-rw-r--r--packages/overlays/AccentColorGreenOverlay/Android.bp9
-rw-r--r--packages/overlays/AccentColorOceanOverlay/Android.bp9
-rw-r--r--packages/overlays/AccentColorOrchidOverlay/Android.bp9
-rw-r--r--packages/overlays/AccentColorPaletteOverlay/Android.bp9
-rw-r--r--packages/overlays/AccentColorPurpleOverlay/Android.bp9
-rw-r--r--packages/overlays/AccentColorSandOverlay/Android.bp9
-rw-r--r--packages/overlays/AccentColorSpaceOverlay/Android.bp9
-rw-r--r--packages/overlays/AccentColorTangerineOverlay/Android.bp9
-rw-r--r--packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.bp9
-rw-r--r--packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.bp9
-rw-r--r--packages/overlays/DisplayCutoutEmulationHoleOverlay/Android.bp9
-rw-r--r--packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.bp9
-rw-r--r--packages/overlays/DisplayCutoutEmulationTallOverlay/Android.bp9
-rw-r--r--packages/overlays/DisplayCutoutEmulationWaterfallOverlay/Android.bp9
-rw-r--r--packages/overlays/DisplayCutoutEmulationWideOverlay/Android.bp9
-rw-r--r--packages/overlays/FontNotoSerifSourceOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackCircularAndroidOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackCircularLauncherOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackCircularSettingsOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackCircularSystemUIOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackCircularThemePickerOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackFilledAndroidOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackFilledLauncherOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackFilledSettingsOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackFilledSystemUIOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackFilledThemePickerOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackKaiAndroidOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackKaiLauncherOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackKaiSettingsOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackKaiSystemUIOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackKaiThemePickerOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackRoundedAndroidOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackRoundedLauncherOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackRoundedSettingsOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackRoundedSystemUIOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackRoundedThemePickerOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackSamAndroidOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackSamLauncherOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackSamSettingsOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackSamSystemUIOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackSamThemePickerOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackVictorAndroidOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackVictorLauncherOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackVictorSettingsOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackVictorSystemUIOverlay/Android.bp9
-rw-r--r--packages/overlays/IconPackVictorThemePickerOverlay/Android.bp9
-rw-r--r--packages/overlays/IconShapeHeartOverlay/Android.bp9
-rw-r--r--packages/overlays/IconShapePebbleOverlay/Android.bp9
-rw-r--r--packages/overlays/IconShapeRoundedRectOverlay/Android.bp9
-rw-r--r--packages/overlays/IconShapeSquareOverlay/Android.bp9
-rw-r--r--packages/overlays/IconShapeSquircleOverlay/Android.bp9
-rw-r--r--packages/overlays/IconShapeTaperedRectOverlay/Android.bp9
-rw-r--r--packages/overlays/IconShapeTeardropOverlay/Android.bp9
-rw-r--r--packages/overlays/IconShapeVesselOverlay/Android.bp9
-rw-r--r--packages/overlays/NavigationBarMode2ButtonOverlay/Android.bp9
-rw-r--r--packages/overlays/NavigationBarMode3ButtonOverlay/Android.bp9
-rw-r--r--packages/overlays/NavigationBarModeGesturalOverlay/Android.bp9
-rw-r--r--packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/Android.bp9
-rw-r--r--packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/Android.bp9
-rw-r--r--packages/overlays/NavigationBarModeGesturalOverlayWideBack/Android.bp9
-rw-r--r--packages/overlays/OneHandedModeGesturalOverlay/Android.bp9
-rw-r--r--packages/services/CameraExtensionsProxy/Android.bp9
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java4
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java2
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java23
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java63
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java11
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java41
-rw-r--r--services/core/java/com/android/server/DynamicSystemService.java9
-rw-r--r--services/core/java/com/android/server/IpSecService.java24
-rw-r--r--services/core/java/com/android/server/VcnManagementService.java7
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java5
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java131
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java81
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java36
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java118
-rw-r--r--services/core/java/com/android/server/apphibernation/AppHibernationService.java52
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java1
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/ReEnrollNotificationUtils.java82
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java8
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java9
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java46
-rw-r--r--services/core/java/com/android/server/connectivity/Nat464Xlat.java7
-rw-r--r--services/core/java/com/android/server/connectivity/PermissionMonitor.java55
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java9
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java25
-rw-r--r--services/core/java/com/android/server/content/SyncOperation.java18
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java4
-rw-r--r--services/core/java/com/android/server/display/BrightnessTracker.java1
-rw-r--r--services/core/java/com/android/server/display/ColorFade.java6
-rw-r--r--services/core/java/com/android/server/display/DisplayDevice.java17
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceConfig.java15
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java73
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java116
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerState.java23
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java164
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplayMapper.java14
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayAdapter.java3
-rw-r--r--services/core/java/com/android/server/display/VirtualDisplayAdapter.java2
-rw-r--r--services/core/java/com/android/server/display/WifiDisplayAdapter.java3
-rw-r--r--services/core/java/com/android/server/hdmi/DeviceSelectAction.java6
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecConfig.java45
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java14
-rw-r--r--services/core/java/com/android/server/hdmi/HotplugDetectionAction.java2
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java208
-rw-r--r--services/core/java/com/android/server/input/OWNERS1
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java8
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java39
-rw-r--r--services/core/java/com/android/server/location/countrydetector/ComprehensiveCountryDetector.java9
-rw-r--r--services/core/java/com/android/server/location/eventlog/LocationEventLog.java51
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssManagerService.java22
-rw-r--r--services/core/java/com/android/server/location/provider/AbstractLocationProvider.java8
-rw-r--r--services/core/java/com/android/server/location/provider/LocationProviderManager.java1
-rw-r--r--services/core/java/com/android/server/locksettings/RebootEscrowManager.java4
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyLogger.java18
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java112
-rw-r--r--services/core/java/com/android/server/notification/NotificationDelegate.java2
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java6
-rw-r--r--services/core/java/com/android/server/notification/SnoozeHelper.java2
-rw-r--r--services/core/java/com/android/server/os/NativeTombstoneManager.java2
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java8
-rw-r--r--services/core/java/com/android/server/pm/DataLoaderManagerService.java16
-rw-r--r--services/core/java/com/android/server/pm/DumpState.java19
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java18
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java707
-rw-r--r--services/core/java/com/android/server/pm/Settings.java7
-rw-r--r--services/core/java/com/android/server/pm/dex/ArtPackageInfo.java58
-rw-r--r--services/core/java/com/android/server/pm/dex/ArtUtils.java64
-rw-r--r--services/core/java/com/android/server/pm/dex/DexManager.java47
-rw-r--r--services/core/java/com/android/server/pm/dex/PackageDexUsage.java13
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java105
-rw-r--r--services/core/java/com/android/server/power/DisplayGroupPowerStateMapper.java280
-rw-r--r--services/core/java/com/android/server/power/DisplayPowerRequestMapper.java121
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java675
-rw-r--r--services/core/java/com/android/server/speech/Android.bp9
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java4
-rw-r--r--services/core/java/com/android/server/vcn/VcnGatewayConnection.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java4
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java108
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java106
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java16
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java12
-rw-r--r--services/core/java/com/android/server/wm/DockedTaskDividerController.java (renamed from services/core/java/com/android/server/wm/DockedStackDividerController.java)8
-rw-r--r--services/core/java/com/android/server/wm/PinnedTaskController.java (renamed from services/core/java/com/android/server/wm/PinnedStackController.java)70
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java8
-rw-r--r--services/core/java/com/android/server/wm/Task.java20
-rw-r--r--services/core/java/com/android/server/wm/TaskChangeNotificationController.java8
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowFrames.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java6
-rw-r--r--services/core/jni/com_android_server_am_CachedAppOptimizer.cpp2
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp113
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java9
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java136
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java26
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java60
-rw-r--r--services/java/com/android/server/SystemServer.java22
-rw-r--r--services/musicrecognition/Android.bp11
-rw-r--r--services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java34
-rw-r--r--services/searchui/Android.bp9
-rw-r--r--services/smartspace/Android.bp9
-rw-r--r--services/tests/PackageManagerServiceTests/host/libs/IntentVerifyUtils/Android.bp9
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp9
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/Android.bp9
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/Android.bp9
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp9
-rw-r--r--services/tests/PackageManagerServiceTests/unit/Android.bp9
-rw-r--r--services/tests/inprocesstests/Android.bp9
-rw-r--r--services/tests/mockingservicestests/jni/Android.bp9
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java87
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java34
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java182
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java276
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java45
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java124
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java36
-rw-r--r--services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java21
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java116
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java63
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java21
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/OWNERS1
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java40
-rw-r--r--services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java118
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java11
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java79
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java2
-rw-r--r--services/texttospeech/Android.bp11
-rw-r--r--services/translation/Android.bp11
-rw-r--r--telecomm/java/android/telecom/Connection.aidl22
-rw-r--r--telecomm/java/android/telecom/Connection.java135
-rwxr-xr-xtelecomm/java/android/telecom/ConnectionService.java36
-rw-r--r--telecomm/java/android/telecom/RemoteConnection.java19
-rw-r--r--telecomm/java/com/android/internal/telecom/IConnectionService.aidl8
-rw-r--r--telephony/java/android/telephony/Annotation.java2
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java2
-rw-r--r--telephony/java/android/telephony/DataFailCause.java4
-rw-r--r--telephony/java/android/telephony/SmsManager.java68
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java44
-rw-r--r--telephony/java/android/telephony/data/DataCallResponse.java68
-rw-r--r--telephony/java/android/telephony/data/DataService.java27
-rw-r--r--telephony/java/android/telephony/data/IDataService.aidl5
-rw-r--r--telephony/java/android/telephony/data/TrafficDescriptor.aidl20
-rw-r--r--telephony/java/android/telephony/data/TrafficDescriptor.java111
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl5
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneConstants.java17
-rw-r--r--test-base/Android.bp11
-rw-r--r--test-base/hiddenapi/Android.bp15
-rw-r--r--tests/BatteryStatsPerfTest/Android.bp9
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt473
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt199
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt198
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt130
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt190
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt236
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt151
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt217
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt78
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt193
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt217
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt10
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt202
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt207
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt207
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt164
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt29
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt193
-rw-r--r--tests/Input/Android.bp9
-rw-r--r--tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt5
-rw-r--r--tests/RollbackTest/Android.bp3
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java8
-rw-r--r--tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java8
-rw-r--r--tests/SilkFX/Android.bp9
-rw-r--r--tests/SurfaceViewBufferTests/Android.bp9
-rw-r--r--tests/UpdatableSystemFontTest/Android.bp9
-rw-r--r--tests/UpdatableSystemFontTest/testdata/Android.bp9
-rw-r--r--tests/benchmarks/internal/Android.bp10
-rw-r--r--tests/net/common/java/android/net/NetworkStackTest.java41
-rw-r--r--tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt9
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java33
-rw-r--r--tests/net/java/com/android/server/IpSecServiceParameterizedTest.java26
-rw-r--r--tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java4
-rw-r--r--tests/net/java/com/android/server/IpSecServiceTest.java9
-rw-r--r--tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java23
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java25
-rw-r--r--tests/vcn/java/android/net/vcn/VcnManagerTest.java7
-rw-r--r--tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java2
-rw-r--r--tests/vcn/java/com/android/server/VcnManagementServiceTest.java10
-rwxr-xr-xtools/fonts/fontchain_linter.py55
-rw-r--r--tools/powerstats/Android.bp9
-rw-r--r--tools/processors/intdef_mappings/Android.bp11
-rw-r--r--tools/xmlpersistence/Android.bp9
706 files changed, 20990 insertions, 11297 deletions
diff --git a/apct-tests/perftests/contentcapture/Android.bp b/apct-tests/perftests/contentcapture/Android.bp
index 19a66ad9f27b..638403d40ea3 100644
--- a/apct-tests/perftests/contentcapture/Android.bp
+++ b/apct-tests/perftests/contentcapture/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test {
name: "ContentCapturePerfTests",
srcs: ["src/**/*.java"],
diff --git a/apct-tests/perftests/inputmethod/Android.bp b/apct-tests/perftests/inputmethod/Android.bp
index 463ac9b8b0c8..f2f1f758112e 100644
--- a/apct-tests/perftests/inputmethod/Android.bp
+++ b/apct-tests/perftests/inputmethod/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test {
name: "ImePerfTests",
srcs: ["src/**/*.java"],
diff --git a/apex/appsearch/Android.bp b/apex/appsearch/Android.bp
index b014fdcb3df3..87f65a922004 100644
--- a/apex/appsearch/Android.bp
+++ b/apex/appsearch/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
apex {
name: "com.android.appsearch",
manifest: "apex_manifest.json",
@@ -21,6 +30,7 @@ apex {
],
key: "com.android.appsearch.key",
certificate: ":com.android.appsearch.certificate",
+ updatable: false,
}
apex_key {
diff --git a/apex/appsearch/framework/Android.bp b/apex/appsearch/framework/Android.bp
index 8ba79541088b..5def55fd31ff 100644
--- a/apex/appsearch/framework/Android.bp
+++ b/apex/appsearch/framework/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
filegroup {
name: "framework-appsearch-sources",
srcs: [
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt
index 905000ac7c3d..cc79f6bf9682 100644
--- a/apex/appsearch/framework/api/current.txt
+++ b/apex/appsearch/framework/api/current.txt
@@ -2,6 +2,7 @@
package android.app.appsearch {
public final class AppSearchBatchResult<KeyType, ValueType> {
+ method @NonNull public java.util.Map<KeyType,android.app.appsearch.AppSearchResult<ValueType>> getAll();
method @NonNull public java.util.Map<KeyType,android.app.appsearch.AppSearchResult<ValueType>> getFailures();
method @NonNull public java.util.Map<KeyType,ValueType> getSuccesses();
method public boolean isSuccess();
@@ -146,7 +147,7 @@ package android.app.appsearch {
method public void put(@NonNull android.app.appsearch.PutDocumentsRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.appsearch.BatchResultCallback<java.lang.String,java.lang.Void>);
method public void remove(@NonNull android.app.appsearch.RemoveByUriRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.appsearch.BatchResultCallback<java.lang.String,java.lang.Void>);
method public void remove(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
- method @NonNull public void reportUsage(@NonNull android.app.appsearch.ReportUsageRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
+ method public void reportUsage(@NonNull android.app.appsearch.ReportUsageRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
method @NonNull public android.app.appsearch.SearchResults search(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor);
method public void setSchema(@NonNull android.app.appsearch.SetSchemaRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.SetSchemaResponse>>);
}
@@ -358,7 +359,6 @@ package android.app.appsearch {
method @NonNull public java.util.Set<java.lang.String> getIncompatibleTypes();
method @NonNull public java.util.Set<java.lang.String> getMigratedTypes();
method @NonNull public java.util.List<android.app.appsearch.SetSchemaResponse.MigrationFailure> getMigrationFailures();
- method public boolean isSuccess();
}
public static class SetSchemaResponse.MigrationFailure {
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
index cd75b1456ba8..31ab259127c3 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
@@ -28,11 +28,19 @@ import java.util.Collections;
import java.util.Map;
/**
- * Provides access to multiple {@link AppSearchResult}s from a batch operation accepting multiple
- * inputs.
+ * Provides results for AppSearch batch operations which encompass multiple documents.
*
- * @param <KeyType> The type of the keys for {@link #getSuccesses} and {@link #getFailures}.
- * @param <ValueType> The type of result objects associated with the keys.
+ * <p>Individual results of a batch operation are separated into two maps: one for successes and one
+ * for failures. For successes, {@link #getSuccesses()} will return a map of keys to instances of
+ * the value type. For failures, {@link #getFailures()} will return a map of keys to {@link
+ * AppSearchResult} objects.
+ *
+ * <p>Alternatively, {@link #getAll()} returns a map of keys to {@link AppSearchResult} objects for
+ * both successes and failures.
+ *
+ * @see AppSearchSession#put
+ * @see AppSearchSession#getByUri
+ * @see AppSearchSession#remove
*/
public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelable {
@NonNull private final Map<KeyType, ValueType> mSuccesses;
@@ -75,8 +83,11 @@ public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelabl
}
/**
- * Returns a {@link Map} of all successful keys mapped to the successful {@link
- * AppSearchResult}s they produced.
+ * Returns a {@link Map} of keys mapped to instances of the value type for all successful
+ * individual results.
+ *
+ * <p>Example: {@link AppSearchSession#getByUri} returns an {@link AppSearchBatchResult}. Each
+ * key (a URI of {@code String} type) will map to a {@link GenericDocument} object.
*
* <p>The values of the {@link Map} will not be {@code null}.
*/
@@ -86,8 +97,8 @@ public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelabl
}
/**
- * Returns a {@link Map} of all failed keys mapped to the failed {@link AppSearchResult}s they
- * produced.
+ * Returns a {@link Map} of keys mapped to instances of {@link AppSearchResult} for all failed
+ * individual results.
*
* <p>The values of the {@link Map} will not be {@code null}.
*/
@@ -97,10 +108,10 @@ public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelabl
}
/**
- * Returns a {@link Map} of all keys mapped to the {@link AppSearchResult}s they produced.
+ * Returns a {@link Map} of keys mapped to instances of {@link AppSearchResult} for all
+ * individual results.
*
* <p>The values of the {@link Map} will not be {@code null}.
- * @hide
*/
@NonNull
public Map<KeyType, AppSearchResult<ValueType>> getAll() {
@@ -150,8 +161,8 @@ public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelabl
/**
* Builder for {@link AppSearchBatchResult} objects.
*
- * @param <KeyType> The type of keys.
- * @param <ValueType> The type of result objects associated with the keys.
+ * <p>Once {@link #build} is called, the instance can no longer be used.
+ *
* @hide
*/
public static final class Builder<KeyType, ValueType> {
@@ -161,9 +172,11 @@ public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelabl
private boolean mBuilt = false;
/**
- * Associates the {@code key} with the given successful return value.
+ * Associates the {@code key} with the provided successful return value.
*
* <p>Any previous mapping for a key, whether success or failure, is deleted.
+ *
+ * @throws IllegalStateException if the builder has already been used.
*/
@NonNull
public Builder<KeyType, ValueType> setSuccess(
@@ -174,9 +187,11 @@ public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelabl
}
/**
- * Associates the {@code key} with the given failure code and error message.
+ * Associates the {@code key} with the provided failure code and error message.
*
* <p>Any previous mapping for a key, whether success or failure, is deleted.
+ *
+ * @throws IllegalStateException if the builder has already been used.
*/
@NonNull
public Builder<KeyType, ValueType> setFailure(
@@ -189,9 +204,11 @@ public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelabl
}
/**
- * Associates the {@code key} with the given {@code result}.
+ * Associates the {@code key} with the provided {@code result}.
*
* <p>Any previous mapping for a key, whether success or failure, is deleted.
+ *
+ * @throws IllegalStateException if the builder has already been used.
*/
@NonNull
public Builder<KeyType, ValueType> setResult(
@@ -210,7 +227,11 @@ public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelabl
return this;
}
- /** Builds an {@link AppSearchBatchResult} from the contents of this {@link Builder}. */
+ /**
+ * Builds an {@link AppSearchBatchResult} object from the contents of this {@link Builder}.
+ *
+ * @throws IllegalStateException if the builder has already been used.
+ */
@NonNull
public AppSearchBatchResult<KeyType, ValueType> build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
index 69d4e536597f..6a5975ef7ff7 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
@@ -36,12 +36,89 @@ import java.util.concurrent.Executor;
import java.util.function.Consumer;
/**
- * This class provides access to the centralized AppSearch index maintained by the system.
+ * Provides access to the centralized AppSearch index maintained by the system.
*
- * <p>Apps can index structured text documents with AppSearch, which can then be retrieved through
- * the query API.
+ * <p>AppSearch is a search library for managing structured data featuring:
+ * <ul>
+ * <li>A fully offline on-device solution
+ * <li>A set of APIs for applications to index documents and retrieve them via full-text search
+ * <li>APIs for applications to allow the System to display their content on system UI surfaces
+ * <li>Similarly, APIs for applications to allow the System to share their content with other
+ * specified applications.
+ * </ul>
+ *
+ * <p>Applications create a database by opening an {@link AppSearchSession}.
+ *
+ * <p>Example:
+ * <pre>
+ * AppSearchManager appSearchManager = context.getSystemService(AppSearchManager.class);
+ *
+ * AppSearchManager.SearchContext searchContext = new AppSearchManager.SearchContext.Builder().
+ * setDatabaseName(dbName).build());
+ * appSearchManager.createSearchSession(searchContext, mExecutor, appSearchSessionResult -&gt; {
+ * mAppSearchSession = appSearchSessionResult.getResultValue();
+ * });</pre>
+ *
+ * <p>After opening the session, a schema must be set in order to define the organizational
+ * structure of data. The schema is set by calling {@link AppSearchSession#setSchema}. The schema
+ * is composed of a collection of {@link AppSearchSchema} objects, each of which defines a unique
+ * type of data.
+ *
+ * <p>Example:
+ * <pre>
+ * AppSearchSchema emailSchemaType = new AppSearchSchema.Builder("Email")
+ * .addProperty(new StringPropertyConfig.Builder("subject")
+ * .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ * .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+ * .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ * .build()
+ * ).build();
+ *
+ * SetSchemaRequest request = new SetSchemaRequest.Builder().addSchema(emailSchemaType).build();
+ * mAppSearchSession.set(request, mExecutor, appSearchResult -&gt; {
+ * if (appSearchResult.isSuccess()) {
+ * //Schema has been successfully set.
+ * }
+ * });</pre>
+ *
+ * <p>The basic unit of data in AppSearch is represented as a {@link GenericDocument} object,
+ * containing a URI, namespace, time-to-live, score, and properties. A namespace organizes a
+ * logical group of documents. For example, a namespace can be created to group documents on a
+ * per-account basis. A URI identifies a single document within a namespace. The combination
+ * of URI and namespace uniquely identifies a {@link GenericDocument} in the database.
+ *
+ * <p>Once the schema has been set, {@link GenericDocument} objects can be put into the database
+ * and indexed by calling {@link AppSearchSession#put}.
+ *
+ * <p>Example:
+ * <pre>
+ * // Although for this example we use GenericDocument directly, we recommend extending
+ * // GenericDocument to create specific types (i.e. Email) with specific setters/getters.
+ * GenericDocument email = new GenericDocument.Builder<>(URI, EMAIL_SCHEMA_TYPE)
+ * .setNamespace(NAMESPACE)
+ * .setPropertyString(“subject”, EMAIL_SUBJECT)
+ * .setScore(EMAIL_SCORE)
+ * .build();
+ *
+ * PutDocumentsRequest request = new PutDocumentsRequest.Builder().addGenericDocuments(email)
+ * .build();
+ * mAppSearchSession.put(request, mExecutor, appSearchBatchResult -&gt; {
+ * if (appSearchBatchResult.isSuccess()) {
+ * //All documents have been successfully indexed.
+ * }
+ * });</pre>
+ *
+ * <p>Searching within the database is done by calling {@link AppSearchSession#search} and providing
+ * the query string to search for, as well as a {@link SearchSpec}.
+ *
+ * <p>Alternatively, {@link AppSearchSession#getByUri} can be called to retrieve documents by URI
+ * and namespace.
+ *
+ * <p>Document removal is done either by time-to-live expiration, or explicitly calling a remove
+ * operation. Remove operations can be done by URI and namespace via
+ * {@link AppSearchSession#remove(RemoveByUriRequest, Executor, BatchResultCallback)},
+ * or by query via {@link AppSearchSession#remove(String, SearchSpec, Executor, Consumer)}.
*/
-// TODO(b/148046169): This class header needs a detailed example/tutorial.
@SystemService(Context.APP_SEARCH_SERVICE)
public class AppSearchManager {
/**
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index 73ca0ccab46d..54f33509072b 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -41,7 +41,7 @@ import java.util.function.Consumer;
* Represents a connection to an AppSearch storage system where {@link GenericDocument}s can be
* placed and queried.
*
- * This class is thread safe.
+ * <p>This class is thread safe.
*/
public final class AppSearchSession implements Closeable {
private static final String TAG = "AppSearchSession";
@@ -102,92 +102,23 @@ public final class AppSearchSession implements Closeable {
}
/**
- * Sets the schema that will be used by documents provided to the {@link #put} method.
- *
- * <p>The schema provided here is compared to the stored copy of the schema previously supplied
- * to {@link #setSchema}, if any, to determine how to treat existing documents. The following
- * types of schema modifications are always safe and are made without deleting any existing
- * documents:
- *
- * <ul>
- * <li>Addition of new types
- * <li>Addition of new {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} or
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} properties to a
- * type
- * <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an {@link
- * AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a {@link
- * AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} property.
- * </ul>
- *
- * <p>The following types of schema changes are not backwards-compatible:
- *
- * <ul>
- * <li>Removal of an existing type
- * <li>Removal of a property from a type
- * <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
- * <li>For properties of {@code Document} type, changing the schema type of {@code Document}s
- * of that property
- * <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an {@link
- * AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a {@link
- * AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property).
- * <li>Adding a {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property.
- * </ul>
- *
- * <p>Supplying a schema with such changes will, by default, result in this call completing its
- * future with an {@link android.app.appsearch.exceptions.AppSearchException} with a code of
- * {@link AppSearchResult#RESULT_INVALID_SCHEMA} and a message describing the incompatibility.
- * In this case the previously set schema will remain active.
- *
- * <p>If you need to make non-backwards-compatible changes as described above, you can either:
- *
- * <ul>
- * <li>Set the {@link SetSchemaRequest.Builder#setForceOverride} method to {@code true}. In
- * this case, instead of completing its future with an {@link
- * android.app.appsearch.exceptions.AppSearchException} with the {@link
- * AppSearchResult#RESULT_INVALID_SCHEMA} error code, all documents which are not
- * compatible with the new schema will be deleted and the incompatible schema will be
- * applied. Incompatible types and deleted types will be set into {@link
- * SetSchemaResponse#getIncompatibleTypes()} and {@link
- * SetSchemaResponse#getDeletedTypes()}, respectively.
- * <li>Add a {@link android.app.appsearch.AppSearchSchema.Migrator} for each incompatible type
- * and make no deletion. The migrator will migrate documents from it's old schema version
- * to the new version. Migrated types will be set into both {@link
- * SetSchemaResponse#getIncompatibleTypes()} and {@link
- * SetSchemaResponse#getMigratedTypes()}. See the migration section below.
- * </ul>
- *
- * <p>It is a no-op to set the same schema as has been previously set; this is handled
- * efficiently.
- *
- * <p>By default, documents are visible on platform surfaces. To opt out, call {@code
- * SetSchemaRequest.Builder#setPlatformSurfaceable} with {@code surfaceable} as false. Any
- * visibility settings apply only to the schemas that are included in the {@code request}.
- * Visibility settings for a schema type do not apply or persist across {@link
- * SetSchemaRequest}s.
- *
- * <p>Migration: make non-backwards-compatible changes will delete all stored documents in old
- * schema. You can save your documents by setting {@link
- * android.app.appsearch.AppSearchSchema.Migrator} via the {@link
- * SetSchemaRequest.Builder#setMigrator} for each type you want to save.
- *
- * <p>{@link android.app.appsearch.AppSearchSchema.Migrator#onDowngrade} or {@link
- * android.app.appsearch.AppSearchSchema.Migrator#onUpgrade} will be triggered if the version
- * number of the schema stored in AppSearch is different with the version in the request.
+ * Sets the schema that represents the organizational structure of data within the AppSearch
+ * database.
*
- * <p>If any error or Exception occurred in the {@link
- * android.app.appsearch.AppSearchSchema.Migrator#onDowngrade}, {@link
- * android.app.appsearch.AppSearchSchema.Migrator#onUpgrade} or {@link
- * android.app.appsearch.AppSearchMigrationHelper.Transformer#transform}, the migration will be
- * terminated, the setSchema request will be rejected unless the schema changes are
- * backwards-compatible, and stored documents won't have any observable changes.
+ * <p>Upon creating an {@link AppSearchSession}, {@link #setSchema} should be called. If the
+ * schema needs to be updated, or it has not been previously set, then the provided schema will
+ * be saved and persisted to disk. Otherwise, {@link #setSchema} is handled efficiently as a
+ * no-op call.
*
- * @param request The schema update request.
+ * @param request the schema to set or update the AppSearch database to.
* @param executor Executor on which to invoke the callback.
* @param callback Callback to receive errors resulting from setting the schema. If the
* operation succeeds, the callback will be invoked with {@code null}.
* @see android.app.appsearch.AppSearchSchema.Migrator
* @see android.app.appsearch.AppSearchMigrationHelper.Transformer
*/
+ // TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are
+ // exposed.
public void setSchema(
@NonNull SetSchemaRequest request,
@NonNull @CallbackExecutor Executor executor,
@@ -280,12 +211,13 @@ public final class AppSearchSession implements Closeable {
}
/**
- * Indexes documents into AppSearch.
+ * Indexes documents into the {@link AppSearchSession} database.
*
- * <p>Each {@link GenericDocument}'s {@code schemaType} field must be set to the name of a
- * schema type previously registered via the {@link #setSchema} method.
+ * <p>Each {@link GenericDocument} object must have a {@code schemaType} field set to an {@link
+ * AppSearchSchema} type that has been previously registered by calling the {@link #setSchema}
+ * method.
*
- * @param request {@link PutDocumentsRequest} containing documents to be indexed
+ * @param request containing documents to be indexed.
* @param executor Executor on which to invoke the callback.
* @param callback Callback to receive pending result of performing this operation. The keys
* of the returned {@link AppSearchBatchResult} are the URIs of the input
@@ -497,7 +429,6 @@ public final class AppSearchSession implements Closeable {
* @param callback Callback to receive errors. If the operation succeeds, the callback will be
* invoked with {@code null}.
*/
- @NonNull
public void reportUsage(
@NonNull ReportUsageRequest request,
@NonNull @CallbackExecutor Executor executor,
diff --git a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
index 09bca4fb3b9d..93b102b864f4 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
@@ -98,8 +98,7 @@ public class GlobalSearchSession implements Closeable {
* <p>Document access can also be granted to system UIs by specifying {@link
* SetSchemaRequest.Builder#setSchemaTypeVisibilityForSystemUi} when building a schema.
*
- * <p>See {@link AppSearchSession#search} for a detailed explanation on
- * forming a query string.
+ * <p>See {@link AppSearchSession#search} for a detailed explanation on forming a query string.
*
* <p>This method is lightweight. The heavy work will be done in {@link
* SearchResults#getNextPage}.
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
index a63e01555f6c..e9e978eea943 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
@@ -33,12 +33,16 @@ import java.util.concurrent.Executor;
import java.util.function.Consumer;
/**
- * SearchResults are a returned object from a query API.
+ * Encapsulates results of a search operation.
*
- * <p>Each {@link SearchResult} contains a document and may contain other fields like snippets based
- * on request.
+ * <p>Each {@link AppSearchSession#search} operation returns a list of {@link SearchResult} objects,
+ * referred to as a "page", limited by the size configured by {@link
+ * SearchSpec.Builder#setResultCountPerPage}.
*
- * <p>Should close this object after finish fetching results.
+ * <p>To fetch a page of results, call {@link #getNextPage}.
+ *
+ * <p>All instances of {@link SearchResults} must call {@link SearchResults#close()} after the
+ * results are fetched.
*
* <p>This class is not thread safe.
*/
@@ -87,12 +91,12 @@ public class SearchResults implements Closeable {
}
/**
- * Gets a whole page of {@link SearchResult}s.
+ * Retrieves the next page of {@link SearchResult} objects.
*
- * <p>Re-call this method to get next page of {@link SearchResult}, until it returns an empty
- * list.
+ * <p>The page size is configured by {@link SearchSpec.Builder#setResultCountPerPage}.
*
- * <p>The page size is set by {@link SearchSpec.Builder#setResultCountPerPage}.
+ * <p>Continue calling this method to access results until it returns an empty list, signifying
+ * there are no more results.
*
* @param callback Callback to receive the pending result of performing this operation.
*/
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
index 138eb23148af..72bb9f3d07c8 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
@@ -583,9 +583,9 @@ public class GenericDocument {
* @param schemaType the {@link AppSearchSchema} type of the {@link GenericDocument}. The
* provided {@code schemaType} must be defined using {@link AppSearchSession#setSchema}
* prior to inserting a document of this {@code schemaType} into the AppSearch index
- * using {@link AppSearchSession#put}. Otherwise, the document will
- * be rejected by {@link AppSearchSession#put} with result code
- * {@link AppSearchResult#RESULT_NOT_FOUND}.
+ * using {@link AppSearchSession#put}. Otherwise, the document will be rejected by
+ * {@link AppSearchSession#put} with result code {@link
+ * AppSearchResult#RESULT_NOT_FOUND}.
*/
@SuppressWarnings("unchecked")
public Builder(@NonNull String uri, @NonNull String schemaType) {
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
index 05b212880962..01473be062bc 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
@@ -28,9 +28,9 @@ import java.util.Collections;
import java.util.List;
/**
- * Encapsulates a request to index a document into an {@link AppSearchSession} database.
+ * Encapsulates a request to index documents into an {@link AppSearchSession} database.
*
- * <p>@see AppSearchSession#putDocuments
+ * @see AppSearchSession#put
*/
public final class PutDocumentsRequest {
private final List<GenericDocument> mDocuments;
@@ -39,7 +39,7 @@ public final class PutDocumentsRequest {
mDocuments = documents;
}
- /** Returns the documents that are part of this request. */
+ /** Returns a list of {@link GenericDocument} objects that are part of this request. */
@NonNull
public List<GenericDocument> getGenericDocuments() {
return Collections.unmodifiableList(mDocuments);
@@ -54,14 +54,22 @@ public final class PutDocumentsRequest {
private final List<GenericDocument> mDocuments = new ArrayList<>();
private boolean mBuilt = false;
- /** Adds one or more {@link GenericDocument} objects to the request. */
+ /**
+ * Adds one or more {@link GenericDocument} objects to the request.
+ *
+ * @throws IllegalStateException if the builder has already been used.
+ */
@NonNull
public Builder addGenericDocuments(@NonNull GenericDocument... documents) {
Preconditions.checkNotNull(documents);
return addGenericDocuments(Arrays.asList(documents));
}
- /** Adds a collection of {@link GenericDocument} objects to the request. */
+ /**
+ * Adds a collection of {@link GenericDocument} objects to the request.
+ *
+ * @throws IllegalStateException if the builder has already been used.
+ */
@NonNull
public Builder addGenericDocuments(
@NonNull Collection<? extends GenericDocument> documents) {
@@ -71,7 +79,11 @@ public final class PutDocumentsRequest {
return this;
}
- /** Creates a new {@link PutDocumentsRequest} object. */
+ /**
+ * Creates a new {@link PutDocumentsRequest} object.
+ *
+ * @throws IllegalStateException if the builder has already been used.
+ */
@NonNull
public PutDocumentsRequest build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
index 2caa94a5ef07..426a903981b3 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
@@ -32,6 +32,41 @@ import java.util.Set;
/**
* Encapsulates a request to update the schema of an {@link AppSearchSession} database.
*
+ * <p>The schema is composed of a collection of {@link AppSearchSchema} objects, each of which
+ * defines a unique type of data.
+ *
+ * <p>The first call to SetSchemaRequest will set the provided schema and store it within the {@link
+ * AppSearchSession} database.
+ *
+ * <p>Subsequent calls will compare the provided schema to the previously saved schema, to determine
+ * how to treat existing documents.
+ *
+ * <p>The following types of schema modifications are always safe and are made without deleting any
+ * existing documents:
+ *
+ * <ul>
+ * <li>Addition of new {@link AppSearchSchema} types
+ * <li>Addition of new properties to an existing {@link AppSearchSchema} type
+ * <li>Changing the cardinality of a property to be less restrictive
+ * </ul>
+ *
+ * <p>The following types of schema changes are not backwards compatible:
+ *
+ * <ul>
+ * <li>Removal of an existing {@link AppSearchSchema} type
+ * <li>Removal of a property from an existing {@link AppSearchSchema} type
+ * <li>Changing the data type of an existing property
+ * <li>Changing the cardinality of a property to be more restrictive
+ * </ul>
+ *
+ * <p>Providing a schema with incompatible changes, will throw an {@link
+ * android.app.appsearch.exceptions.AppSearchException}, with a message describing the
+ * incompatibility. As a result, the previously set schema will remain unchanged.
+ *
+ * <p>Backward incompatible changes can be made by setting {@link
+ * SetSchemaRequest.Builder#setForceOverride} method to {@code true}. This deletes all documents
+ * that are incompatible with the new schema. The new schema is then saved and persisted to disk.
+ *
* @see AppSearchSession#setSchema
*/
public final class SetSchemaRequest {
@@ -54,14 +89,15 @@ public final class SetSchemaRequest {
mForceOverride = forceOverride;
}
- /** Returns the schemas that are part of this request. */
+ /** Returns the {@link AppSearchSchema} types that are part of this request. */
@NonNull
public Set<AppSearchSchema> getSchemas() {
return Collections.unmodifiableSet(mSchemas);
}
/**
- * Returns the set of schema types that have opted out of being visible on system UI surfaces.
+ * Returns all the schema types that are opted out of being displayed and visible on any system
+ * UI surface.
*/
@NonNull
public Set<String> getSchemasNotVisibleToSystemUi() {
@@ -70,10 +106,9 @@ public final class SetSchemaRequest {
/**
* Returns a mapping of schema types to the set of packages that have access to that schema
- * type. Each package is represented by a {@link PackageIdentifier}. name and byte[]
- * certificate.
+ * type.
*
- * <p>This method is inefficient to call repeatedly.
+ * <p>It’s inefficient to call this method repeatedly.
*/
@NonNull
public Map<String, Set<PackageIdentifier>> getSchemasVisibleToPackages() {
@@ -91,9 +126,8 @@ public final class SetSchemaRequest {
}
/**
- * Returns a mapping of schema types to the set of packages that have access to that schema
- * type. Each package is represented by a {@link PackageIdentifier}. name and byte[]
- * certificate.
+ * Returns a mapping of {@link AppSearchSchema} types to the set of packages that have access to
+ * that schema type.
*
* <p>A more efficient version of {@link #getSchemasVisibleToPackages}, but it returns a
* modifiable map. This is not meant to be unhidden and should only be used by internal classes.
@@ -110,7 +144,11 @@ public final class SetSchemaRequest {
return mForceOverride;
}
- /** Builder for {@link SetSchemaRequest} objects. */
+ /**
+ * Builder for {@link SetSchemaRequest} objects.
+ *
+ * <p>Once {@link #build} is called, the instance can no longer be used.
+ */
public static final class Builder {
private final Set<AppSearchSchema> mSchemas = new ArraySet<>();
private final Set<String> mSchemasNotVisibleToSystemUi = new ArraySet<>();
@@ -121,9 +159,11 @@ public final class SetSchemaRequest {
private boolean mBuilt = false;
/**
- * Adds one or more types to the schema.
+ * Adds one or more {@link AppSearchSchema} types to the schema.
+ *
+ * <p>An {@link AppSearchSchema} object represents one type of structured data.
*
- * <p>Any documents of these types will be visible on system UI surfaces by default.
+ * @throws IllegalStateException if the builder has already been used.
*/
@NonNull
public Builder addSchemas(@NonNull AppSearchSchema... schemas) {
@@ -132,9 +172,11 @@ public final class SetSchemaRequest {
}
/**
- * Adds one or more types to the schema.
+ * Adds a collection of {@link AppSearchSchema} objects to the schema.
*
- * <p>Any documents of these types will be visible on system UI surfaces by default.
+ * <p>An {@link AppSearchSchema} object represents one type of structured data.
+ *
+ * @throws IllegalStateException if the builder has already been used.
*/
@NonNull
public Builder addSchemas(@NonNull Collection<AppSearchSchema> schemas) {
@@ -145,10 +187,17 @@ public final class SetSchemaRequest {
}
/**
- * Sets visibility on system UI surfaces for the given {@code schemaType}.
+ * Sets whether or not documents from the provided {@code schemaType} will be displayed and
+ * visible on any system UI surface.
+ *
+ * <p>This setting applies to the provided {@code schemaType} only, and does not persist
+ * across {@link AppSearchSession#setSchema} calls.
+ *
+ * <p>By default, documents are displayed and visible on system UI surfaces.
*
* @param schemaType The schema type to set visibility on.
* @param visible Whether the {@code schemaType} will be visible or not.
+ * @throws IllegalStateException if the builder has already been used.
*/
// Merged list available from getSchemasNotVisibleToSystemUi
@SuppressLint("MissingGetterMatchingBuilder")
@@ -167,11 +216,25 @@ public final class SetSchemaRequest {
}
/**
- * Sets visibility for a package for the given {@code schemaType}.
+ * Sets whether or not documents from the provided {@code schemaType} can be read by the
+ * specified package.
+ *
+ * <p>Each package is represented by a {@link PackageIdentifier}, containing a package name
+ * and a byte array of type {@link android.content.pm.PackageManager#CERT_INPUT_SHA256}.
+ *
+ * <p>To opt into one-way data sharing with another application, the developer will need to
+ * explicitly grant the other application’s package name and certificate Read access to its
+ * data.
+ *
+ * <p>For two-way data sharing, both applications need to explicitly grant Read access to
+ * one another.
+ *
+ * <p>By default, data sharing between applications is disabled.
*
* @param schemaType The schema type to set visibility on.
* @param visible Whether the {@code schemaType} will be visible or not.
* @param packageIdentifier Represents the package that will be granted visibility.
+ * @throws IllegalStateException if the builder has already been used.
*/
// Merged list available from getSchemasVisibleToPackages
@SuppressLint("MissingGetterMatchingBuilder")
@@ -224,13 +287,15 @@ public final class SetSchemaRequest {
}
/**
- * Configures the {@link SetSchemaRequest} to delete any existing documents that don't
- * follow the new schema.
+ * Sets whether or not to override the current schema in the {@link AppSearchSession}
+ * database.
*
- * <p>By default, this is {@code false} and schema incompatibility causes the {@link
- * AppSearchSession#setSchema} call to fail.
+ * <p>Call this method whenever backward incompatible changes need to be made by setting
+ * {@code forceOverride} to {@code true}. As a result, during execution of the setSchema
+ * operation, all documents that are incompatible with the new schema will be deleted and
+ * the new schema will be saved and persisted.
*
- * @see AppSearchSession#setSchema
+ * <p>By default, this is {@code false}.
*/
@NonNull
public Builder setForceOverride(boolean forceOverride) {
@@ -239,10 +304,11 @@ public final class SetSchemaRequest {
}
/**
- * Builds a new {@link SetSchemaRequest}.
+ * Builds a new {@link SetSchemaRequest} object.
*
- * @throws IllegalArgumentException If schema types were referenced, but the corresponding
- * {@link AppSearchSchema} was never added.
+ * @throws IllegalArgumentException if schema types were referenced, but the corresponding
+ * {@link AppSearchSchema} type was never added.
+ * @throws IllegalStateException if the builder has already been used.
*/
@NonNull
public SetSchemaRequest build() {
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
index bc99d4f67d86..a146006f355c 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
@@ -79,12 +79,6 @@ public class SetSchemaResponse {
return mBundle;
}
- /** TODO(b/177266929): Remove this deprecated method */
- //@Deprecated
- public boolean isSuccess() {
- return true;
- }
-
/**
* Returns a {@link List} of all failed {@link MigrationFailure}.
*
diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp
index 2fd5c733473e..57ee1ec482d8 100644
--- a/apex/appsearch/service/Android.bp
+++ b/apex/appsearch/service/Android.bp
@@ -11,6 +11,15 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
java_library {
name: "service-appsearch",
installable: true,
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
index babcd25e3e26..7c92456bea49 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
@@ -218,9 +218,23 @@ public class VisibilityStore {
* @throws AppSearchException AppSearchException on AppSearchImpl error.
*/
public void initialize() throws AppSearchException {
- if (!mAppSearchImpl.hasSchemaTypeLocked(PACKAGE_NAME, DATABASE_NAME, VISIBILITY_TYPE)
- || !mAppSearchImpl.hasSchemaTypeLocked(
- PACKAGE_NAME, DATABASE_NAME, PACKAGE_ACCESSIBLE_TYPE)) {
+ List<AppSearchSchema> schemas = mAppSearchImpl.getSchema(PACKAGE_NAME, DATABASE_NAME);
+ boolean hasVisibilityType = false;
+ boolean hasPackageAccessibleType = false;
+ for (int i = 0; i < schemas.size(); i++) {
+ AppSearchSchema schema = schemas.get(i);
+ if (schema.getSchemaType().equals(VISIBILITY_TYPE)) {
+ hasVisibilityType = true;
+ } else if (schema.getSchemaType().equals(PACKAGE_ACCESSIBLE_TYPE)) {
+ hasPackageAccessibleType = true;
+ }
+
+ if (hasVisibilityType && hasPackageAccessibleType) {
+ // Found both our types, can exit early.
+ break;
+ }
+ }
+ if (!hasVisibilityType || !hasPackageAccessibleType) {
// Schema type doesn't exist yet. Add it.
mAppSearchImpl.setSchema(
PACKAGE_NAME,
@@ -250,10 +264,11 @@ public class VisibilityStore {
/*typePropertyPaths=*/ Collections.emptyMap());
// Update platform visibility settings
- String[] schemas =
+ String[] notPlatformSurfaceableSchemas =
document.getPropertyStringArray(NOT_PLATFORM_SURFACEABLE_PROPERTY);
- if (schemas != null) {
- mNotPlatformSurfaceableMap.put(prefix, new ArraySet<>(Arrays.asList(schemas)));
+ if (notPlatformSurfaceableSchemas != null) {
+ mNotPlatformSurfaceableMap.put(
+ prefix, new ArraySet<>(Arrays.asList(notPlatformSurfaceableSchemas)));
}
// Update 3p package visibility settings
@@ -333,7 +348,7 @@ public class VisibilityStore {
schemasPackageAccessible.entrySet()) {
for (int i = 0; i < entry.getValue().size(); i++) {
GenericDocument packageAccessibleDocument =
- new GenericDocument.Builder(/*uri=*/"", PACKAGE_ACCESSIBLE_TYPE)
+ new GenericDocument.Builder(/*uri=*/ "", PACKAGE_ACCESSIBLE_TYPE)
.setNamespace(NAMESPACE)
.setPropertyString(
PACKAGE_NAME_PROPERTY,
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index 6c2e30e98877..e2c211b7d303 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -654,6 +654,35 @@ public final class AppSearchImpl implements Closeable {
}
}
+ /**
+ * Returns a mapping of package names to all the databases owned by that package.
+ *
+ * <p>This method is inefficient to call repeatedly.
+ */
+ @NonNull
+ public Map<String, Set<String>> getPackageToDatabases() {
+ mReadWriteLock.readLock().lock();
+ try {
+ Map<String, Set<String>> packageToDatabases = new ArrayMap<>();
+ for (String prefix : mSchemaMapLocked.keySet()) {
+ String packageName = getPackageName(prefix);
+
+ Set<String> databases = packageToDatabases.get(packageName);
+ if (databases == null) {
+ databases = new ArraySet<>();
+ packageToDatabases.put(packageName, databases);
+ }
+
+ String databaseName = getDatabaseName(prefix);
+ databases.add(databaseName);
+ }
+
+ return packageToDatabases;
+ } finally {
+ mReadWriteLock.readLock().unlock();
+ }
+ }
+
@GuardedBy("mReadWriteLock")
private SearchResultPage doQueryLocked(
@NonNull Set<String> prefixes,
@@ -1211,26 +1240,8 @@ public final class AppSearchImpl implements Closeable {
return schemaProto.getSchema();
}
- /**
- * Returns true if the {@code packageName} and {@code databaseName} has the {@code schemaType}
- */
- @GuardedBy("mReadWriteLock")
- boolean hasSchemaTypeLocked(
- @NonNull String packageName, @NonNull String databaseName, @NonNull String schemaType) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(databaseName);
- Preconditions.checkNotNull(schemaType);
-
- String prefix = createPrefix(packageName, databaseName);
- Set<String> schemaTypes = mSchemaMapLocked.get(prefix);
- if (schemaTypes == null) {
- return false;
- }
-
- return schemaTypes.contains(prefix + schemaType);
- }
-
/** Returns a set of all prefixes AppSearchImpl knows about. */
+ // TODO(b/180058203): Remove this method once platform has switched away from using this method.
@GuardedBy("mReadWriteLock")
@NonNull
Set<String> getPrefixesLocked() {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java
new file mode 100644
index 000000000000..0f23d926648b
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appsearch.external.localstorage;
+
+import android.annotation.NonNull;
+import android.app.appsearch.exceptions.AppSearchException;
+
+import com.android.server.appsearch.external.localstorage.stats.CallStats;
+import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
+
+/**
+ * An interface for implementing client-defined logging AppSearch operations stats.
+ *
+ * <p>Any implementation needs to provide general information on how to log all the stats types.
+ * (e.g. {@link CallStats})
+ *
+ * <p>All implementations of this interface must be thread safe.
+ *
+ * @hide
+ */
+public interface AppSearchLogger {
+ /** Logs {@link CallStats} */
+ void logStats(@NonNull CallStats stats) throws AppSearchException;
+
+ /** Logs {@link PutDocumentStats} */
+ void logStats(@NonNull PutDocumentStats stats) throws AppSearchException;
+
+ // TODO(b/173532925) Add remaining logStats once we add all the stats.
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchMigrationHelperImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchMigrationHelperImpl.java
index a501e99db1ef..a7f1cc4c793f 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchMigrationHelperImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchMigrationHelperImpl.java
@@ -76,7 +76,7 @@ class AppSearchMigrationHelperImpl implements AppSearchMigrationHelper {
int currentVersion = mCurrentVersionMap.get(schemaType);
int finalVersion = mFinalVersionMap.get(schemaType);
try (FileOutputStream outputStream = new FileOutputStream(mFile)) {
- // TODO(b/177266929) change the output stream so that we can use it in platform
+ // TODO(b/151178558) change the output stream so that we can use it in platform
CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(outputStream);
SearchResultPage searchResultPage =
mAppSearchImpl.query(
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java
new file mode 100644
index 000000000000..81a5067c9fa1
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appsearch.external.localstorage.stats;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A class for setting basic information to log for all function calls.
+ *
+ * <p>This class can set which stats to log for both batch and non-batch {@link
+ * android.app.appsearch.AppSearchSession} calls.
+ *
+ * <p>Some function calls like {@link android.app.appsearch.AppSearchSession#setSchema} have their
+ * own detailed stats class {@link placeholder}. However, {@link CallStats} can still be used along
+ * with the detailed stats class for easy aggregation/analysis with other function calls.
+ *
+ * @hide
+ */
+public class CallStats {
+ @IntDef(
+ value = {
+ CALL_TYPE_UNKNOWN,
+ CALL_TYPE_INITIALIZE,
+ CALL_TYPE_SET_SCHEMA,
+ CALL_TYPE_PUT_DOCUMENTS,
+ CALL_TYPE_GET_DOCUMENTS,
+ CALL_TYPE_REMOVE_DOCUMENTS,
+ CALL_TYPE_PUT_DOCUMENT,
+ CALL_TYPE_GET_DOCUMENT,
+ CALL_TYPE_REMOVE_DOCUMENT,
+ CALL_TYPE_QUERY,
+ CALL_TYPE_OPTIMIZE,
+ CALL_TYPE_FLUSH,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CallType {}
+
+ public static final int CALL_TYPE_UNKNOWN = 0;
+ public static final int CALL_TYPE_INITIALIZE = 1;
+ public static final int CALL_TYPE_SET_SCHEMA = 2;
+ public static final int CALL_TYPE_PUT_DOCUMENTS = 3;
+ public static final int CALL_TYPE_GET_DOCUMENTS = 4;
+ public static final int CALL_TYPE_REMOVE_DOCUMENTS = 5;
+ public static final int CALL_TYPE_PUT_DOCUMENT = 6;
+ public static final int CALL_TYPE_GET_DOCUMENT = 7;
+ public static final int CALL_TYPE_REMOVE_DOCUMENT = 8;
+ public static final int CALL_TYPE_QUERY = 9;
+ public static final int CALL_TYPE_OPTIMIZE = 10;
+ public static final int CALL_TYPE_FLUSH = 11;
+
+ @NonNull private final GeneralStats mGeneralStats;
+ @CallType private final int mCallType;
+ private final int mEstimatedBinderLatencyMillis;
+ private final int mNumOperationsSucceeded;
+ private final int mNumOperationsFailed;
+
+ CallStats(@NonNull Builder builder) {
+ Preconditions.checkNotNull(builder);
+ mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStats);
+ mCallType = builder.mCallType;
+ mEstimatedBinderLatencyMillis = builder.mEstimatedBinderLatencyMillis;
+ mNumOperationsSucceeded = builder.mNumOperationsSucceeded;
+ mNumOperationsFailed = builder.mNumOperationsFailed;
+ }
+
+ /** Returns general information for the call. */
+ @NonNull
+ public GeneralStats getGeneralStats() {
+ return mGeneralStats;
+ }
+
+ /** Returns type of the call. */
+ @CallType
+ public int getCallType() {
+ return mCallType;
+ }
+
+ /** Returns estimated binder latency, in milliseconds */
+ public int getEstimatedBinderLatencyMillis() {
+ return mEstimatedBinderLatencyMillis;
+ }
+
+ /**
+ * Returns number of operations succeeded.
+ *
+ * <p>For example, for {@link android.app.appsearch.AppSearchSession#put}, it is the total
+ * number of individual successful put operations. In this case, how many documents are
+ * successfully indexed.
+ *
+ * <p>For non-batch calls such as {@link android.app.appsearch.AppSearchSession#setSchema}, the
+ * sum of {@link CallStats#getNumOperationsSucceeded()} and {@link
+ * CallStats#getNumOperationsFailed()} is always 1 since there is only one operation.
+ */
+ public int getNumOperationsSucceeded() {
+ return mNumOperationsSucceeded;
+ }
+
+ /**
+ * Returns number of operations failed.
+ *
+ * <p>For example, for {@link android.app.appsearch.AppSearchSession#put}, it is the total
+ * number of individual failed put operations. In this case, how many documents are failed to be
+ * indexed.
+ *
+ * <p>For non-batch calls such as {@link android.app.appsearch.AppSearchSession#setSchema}, the
+ * sum of {@link CallStats#getNumOperationsSucceeded()} and {@link
+ * CallStats#getNumOperationsFailed()} is always 1 since there is only one operation.
+ */
+ public int getNumOperationsFailed() {
+ return mNumOperationsFailed;
+ }
+
+ /** Builder for {@link CallStats}. */
+ public static class Builder {
+ @NonNull final GeneralStats mGeneralStats;
+ @CallType int mCallType;
+ int mEstimatedBinderLatencyMillis;
+ int mNumOperationsSucceeded;
+ int mNumOperationsFailed;
+
+ /** Builder takes {@link GeneralStats} to hold general stats. */
+ public Builder(@NonNull GeneralStats generalStats) {
+ mGeneralStats = Preconditions.checkNotNull(generalStats);
+ }
+
+ /** Sets type of the call. */
+ @NonNull
+ public Builder setCallType(@CallType int callType) {
+ mCallType = callType;
+ return this;
+ }
+
+ /** Sets estimated binder latency, in milliseconds. */
+ @NonNull
+ public Builder setEstimatedBinderLatencyMillis(int estimatedBinderLatencyMillis) {
+ mEstimatedBinderLatencyMillis = estimatedBinderLatencyMillis;
+ return this;
+ }
+
+ /**
+ * Sets number of operations succeeded.
+ *
+ * <p>For example, for {@link android.app.appsearch.AppSearchSession#put}, it is the total
+ * number of individual successful put operations. In this case, how many documents are
+ * successfully indexed.
+ *
+ * <p>For non-batch calls such as {@link android.app.appsearch.AppSearchSession#setSchema},
+ * the sum of {@link CallStats#getNumOperationsSucceeded()} and {@link
+ * CallStats#getNumOperationsFailed()} is always 1 since there is only one operation.
+ */
+ @NonNull
+ public Builder setNumOperationsSucceeded(int numOperationsSucceeded) {
+ mNumOperationsSucceeded = numOperationsSucceeded;
+ return this;
+ }
+
+ /**
+ * Sets number of operations failed.
+ *
+ * <p>For example, for {@link android.app.appsearch.AppSearchSession#put}, it is the total
+ * number of individual failed put operations. In this case, how many documents are failed
+ * to be indexed.
+ *
+ * <p>For non-batch calls such as {@link android.app.appsearch.AppSearchSession#setSchema},
+ * the sum of {@link CallStats#getNumOperationsSucceeded()} and {@link
+ * CallStats#getNumOperationsFailed()} is always 1 since there is only one operation.
+ */
+ @NonNull
+ public Builder setNumOperationsFailed(int numOperationsFailed) {
+ mNumOperationsFailed = numOperationsFailed;
+ return this;
+ }
+
+ /** Creates {@link CallStats} object from {@link Builder} instance. */
+ @NonNull
+ public CallStats build() {
+ return new CallStats(/* builder= */ this);
+ }
+ }
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java
new file mode 100644
index 000000000000..d2a45d5304f9
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appsearch.external.localstorage.stats;
+
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchResult;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A class for holding general logging information.
+ *
+ * <p>This class cannot be logged by {@link
+ * com.android.server.appsearch.external.localstorage.AppSearchLogger} directly. It is used for
+ * defining general logging information that is shared across different stats classes.
+ *
+ * @see PutDocumentStats
+ * @see CallStats
+ * @hide
+ */
+public final class GeneralStats {
+ /** Package name of the application. */
+ @NonNull private final String mPackageName;
+
+ /** Database name within AppSearch. */
+ @NonNull private final String mDatabase;
+
+ /**
+ * The status code returned by {@link AppSearchResult#getResultCode()} for the call or internal
+ * state.
+ */
+ @AppSearchResult.ResultCode private final int mStatusCode;
+
+ private final int mTotalLatencyMillis;
+
+ GeneralStats(@NonNull Builder builder) {
+ Preconditions.checkNotNull(builder);
+ mPackageName = Preconditions.checkNotNull(builder.mPackageName);
+ mDatabase = Preconditions.checkNotNull(builder.mDatabase);
+ mStatusCode = builder.mStatusCode;
+ mTotalLatencyMillis = builder.mTotalLatencyMillis;
+ }
+
+ /** Returns package name. */
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /** Returns database name. */
+ @NonNull
+ public String getDatabase() {
+ return mDatabase;
+ }
+
+ /** Returns result code from {@link AppSearchResult#getResultCode()} */
+ @AppSearchResult.ResultCode
+ public int getStatusCode() {
+ return mStatusCode;
+ }
+
+ /** Returns total latency, in milliseconds. */
+ public int getTotalLatencyMillis() {
+ return mTotalLatencyMillis;
+ }
+
+ /** Builder for {@link GeneralStats}. */
+ public static class Builder {
+ @NonNull final String mPackageName;
+ @NonNull final String mDatabase;
+ @AppSearchResult.ResultCode int mStatusCode;
+ int mTotalLatencyMillis;
+
+ /**
+ * Constructor
+ *
+ * @param packageName name of the package logging stats
+ * @param dataBase name of the database logging stats
+ */
+ public Builder(@NonNull String packageName, @NonNull String dataBase) {
+ mPackageName = Preconditions.checkNotNull(packageName);
+ mDatabase = Preconditions.checkNotNull(dataBase);
+ }
+
+ /** Sets status code returned from {@link AppSearchResult#getResultCode()} */
+ @NonNull
+ public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
+ mStatusCode = statusCode;
+ return this;
+ }
+
+ /** Sets total latency, in milliseconds. */
+ @NonNull
+ public Builder setTotalLatencyMillis(int totalLatencyMillis) {
+ mTotalLatencyMillis = totalLatencyMillis;
+ return this;
+ }
+
+ /**
+ * Creates a new {@link GeneralStats} object from the contents of this {@link Builder}
+ * instance.
+ */
+ @NonNull
+ public GeneralStats build() {
+ return new GeneralStats(/* builder= */ this);
+ }
+ }
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java
new file mode 100644
index 000000000000..b1b643b66859
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appsearch.external.localstorage.stats;
+
+import android.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A class for holding detailed stats to log for each individual document put by a {@link
+ * android.app.appsearch.AppSearchSession#put} call.
+ *
+ * @hide
+ */
+public final class PutDocumentStats {
+ /** {@link GeneralStats} holds the general stats. */
+ @NonNull private final GeneralStats mGeneralStats;
+
+ /** Time used to generate a document proto from a Bundle. */
+ private final int mGenerateDocumentProtoLatencyMillis;
+
+ /** Time used to rewrite types and namespaces in the document. */
+ private final int mRewriteDocumentTypesLatencyMillis;
+
+ /** Overall time used for the native function call. */
+ private final int mNativeLatencyMillis;
+
+ /** Time used to store the document. */
+ private final int mNativeDocumentStoreLatencyMillis;
+
+ /** Time used to index the document. It doesn't include the time to merge indices. */
+ private final int mNativeIndexLatencyMillis;
+
+ /** Time used to merge the indices. */
+ private final int mNativeIndexMergeLatencyMillis;
+
+ /** Document size in bytes. */
+ private final int mNativeDocumentSizeBytes;
+
+ /** Number of tokens added to the index. */
+ private final int mNativeNumTokensIndexed;
+
+ /** Number of tokens clipped for exceeding the max number. */
+ private final int mNativeNumTokensClipped;
+
+ PutDocumentStats(@NonNull Builder builder) {
+ Preconditions.checkNotNull(builder);
+ mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStats);
+ mGenerateDocumentProtoLatencyMillis = builder.mGenerateDocumentProtoLatencyMillis;
+ mRewriteDocumentTypesLatencyMillis = builder.mRewriteDocumentTypesLatencyMillis;
+ mNativeLatencyMillis = builder.mNativeLatencyMillis;
+ mNativeDocumentStoreLatencyMillis = builder.mNativeDocumentStoreLatencyMillis;
+ mNativeIndexLatencyMillis = builder.mNativeIndexLatencyMillis;
+ mNativeIndexMergeLatencyMillis = builder.mNativeIndexMergeLatencyMillis;
+ mNativeDocumentSizeBytes = builder.mNativeDocumentSizeBytes;
+ mNativeNumTokensIndexed = builder.mNativeNumTokensIndexed;
+ mNativeNumTokensClipped = builder.mNativeNumTokensClipped;
+ }
+
+ /** Returns the {@link GeneralStats} object attached to this instance. */
+ @NonNull
+ public GeneralStats getGeneralStats() {
+ return mGeneralStats;
+ }
+
+ /** Returns time spent on generating document proto, in milliseconds. */
+ public int getGenerateDocumentProtoLatencyMillis() {
+ return mGenerateDocumentProtoLatencyMillis;
+ }
+
+ /** Returns time spent on rewriting types and namespaces in document, in milliseconds. */
+ public int getRewriteDocumentTypesLatencyMillis() {
+ return mRewriteDocumentTypesLatencyMillis;
+ }
+
+ /** Returns time spent in native, in milliseconds. */
+ public int getNativeLatencyMillis() {
+ return mNativeLatencyMillis;
+ }
+
+ /** Returns time spent on document store, in milliseconds. */
+ public int getNativeDocumentStoreLatencyMillis() {
+ return mNativeDocumentStoreLatencyMillis;
+ }
+
+ /** Returns time spent on indexing, in milliseconds. */
+ public int getNativeIndexLatencyMillis() {
+ return mNativeIndexLatencyMillis;
+ }
+
+ /** Returns time spent on merging indices, in milliseconds. */
+ public int getNativeIndexMergeLatencyMillis() {
+ return mNativeIndexMergeLatencyMillis;
+ }
+
+ /** Returns document size, in bytes. */
+ public int getNativeDocumentSizeBytes() {
+ return mNativeDocumentSizeBytes;
+ }
+
+ /** Returns number of tokens indexed. */
+ public int getNativeNumTokensIndexed() {
+ return mNativeNumTokensIndexed;
+ }
+
+ /** Returns number of tokens clipped for exceeding the max number. */
+ public int getNativeNumTokensClipped() {
+ return mNativeNumTokensClipped;
+ }
+
+ /** Builder for {@link PutDocumentStats}. */
+ public static class Builder {
+ @NonNull final GeneralStats mGeneralStats;
+ int mGenerateDocumentProtoLatencyMillis;
+ int mRewriteDocumentTypesLatencyMillis;
+ int mNativeLatencyMillis;
+ int mNativeDocumentStoreLatencyMillis;
+ int mNativeIndexLatencyMillis;
+ int mNativeIndexMergeLatencyMillis;
+ int mNativeDocumentSizeBytes;
+ int mNativeNumTokensIndexed;
+ int mNativeNumTokensClipped;
+
+ /** Builder takes {@link GeneralStats} to hold general stats. */
+ public Builder(@NonNull GeneralStats generalStats) {
+ mGeneralStats = Preconditions.checkNotNull(generalStats);
+ }
+
+ /** Sets how much time we spend for generating document proto, in milliseconds. */
+ @NonNull
+ public Builder setGenerateDocumentProtoLatencyMillis(
+ int generateDocumentProtoLatencyMillis) {
+ mGenerateDocumentProtoLatencyMillis = generateDocumentProtoLatencyMillis;
+ return this;
+ }
+
+ /**
+ * Sets how much time we spend for rewriting types and namespaces in document, in
+ * milliseconds.
+ */
+ @NonNull
+ public Builder setRewriteDocumentTypesLatencyMillis(int rewriteDocumentTypesLatencyMillis) {
+ mRewriteDocumentTypesLatencyMillis = rewriteDocumentTypesLatencyMillis;
+ return this;
+ }
+
+ /** Sets the native latency, in milliseconds. */
+ @NonNull
+ public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
+ mNativeLatencyMillis = nativeLatencyMillis;
+ return this;
+ }
+
+ /** Sets how much time we spend on document store, in milliseconds. */
+ @NonNull
+ public Builder setNativeDocumentStoreLatencyMillis(int nativeDocumentStoreLatencyMillis) {
+ mNativeDocumentStoreLatencyMillis = nativeDocumentStoreLatencyMillis;
+ return this;
+ }
+
+ /** Sets the native index latency, in milliseconds. */
+ @NonNull
+ public Builder setNativeIndexLatencyMillis(int nativeIndexLatencyMillis) {
+ mNativeIndexLatencyMillis = nativeIndexLatencyMillis;
+ return this;
+ }
+
+ /** Sets how much time we spend on merging indices, in milliseconds. */
+ @NonNull
+ public Builder setNativeIndexMergeLatencyMillis(int nativeIndexMergeLatencyMillis) {
+ mNativeIndexMergeLatencyMillis = nativeIndexMergeLatencyMillis;
+ return this;
+ }
+
+ /** Sets document size, in bytes. */
+ @NonNull
+ public Builder setNativeDocumentSizeBytes(int nativeDocumentSizeBytes) {
+ mNativeDocumentSizeBytes = nativeDocumentSizeBytes;
+ return this;
+ }
+
+ /** Sets number of tokens indexed in native. */
+ @NonNull
+ public Builder setNativeNumTokensIndexed(int nativeNumTokensIndexed) {
+ mNativeNumTokensIndexed = nativeNumTokensIndexed;
+ return this;
+ }
+
+ /** Sets number of tokens clipped for exceeding the max number. */
+ @NonNull
+ public Builder setNativeNumTokensClipped(int nativeNumTokensClipped) {
+ mNativeNumTokensClipped = nativeNumTokensClipped;
+ return this;
+ }
+
+ /**
+ * Creates a new {@link PutDocumentStats} object from the contents of this {@link Builder}
+ * instance.
+ */
+ @NonNull
+ public PutDocumentStats build() {
+ return new PutDocumentStats(/* builder= */ this);
+ }
+ }
+}
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index d076db3b8f82..2c9477a5d76b 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-Ia9a8daef1a6d7d9432f7808d440abd64f4797701
+I593dfd22279739e5f578e07d36a55cf02ee942c5
diff --git a/apex/appsearch/testing/Android.bp b/apex/appsearch/testing/Android.bp
index 54d50395e3bd..eb072afec696 100644
--- a/apex/appsearch/testing/Android.bp
+++ b/apex/appsearch/testing/Android.bp
@@ -11,6 +11,15 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
java_library {
name: "AppSearchTestUtils",
srcs: ["java/**/*.java"],
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
index ea21e19b2bea..1428fb1d3c7a 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
@@ -33,91 +33,19 @@ import java.util.Set;
public interface AppSearchSessionShim extends Closeable {
/**
- * Sets the schema that will be used by documents provided to the {@link #put} method.
+ * Sets the schema that represents the organizational structure of data within the AppSearch
+ * database.
*
- * <p>The schema provided here is compared to the stored copy of the schema previously supplied
- * to {@link #setSchema}, if any, to determine how to treat existing documents. The following
- * types of schema modifications are always safe and are made without deleting any existing
- * documents:
+ * <p>Upon creating an {@link AppSearchSessionShim}, {@link #setSchema} should be called. If the
+ * schema needs to be updated, or it has not been previously set, then the provided schema will
+ * be saved and persisted to disk. Otherwise, {@link #setSchema} is handled efficiently as a
+ * no-op call.
*
- * <ul>
- * <li>Addition of new types
- * <li>Addition of new {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} or
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} properties to a
- * type
- * <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an {@link
- * AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a {@link
- * AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} property.
- * </ul>
- *
- * <p>The following types of schema changes are not backwards-compatible:
- *
- * <ul>
- * <li>Removal of an existing type
- * <li>Removal of a property from a type
- * <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
- * <li>For properties of {@code Document} type, changing the schema type of {@code Document}s
- * of that property
- * <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an {@link
- * AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a {@link
- * AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property).
- * <li>Adding a {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property.
- * </ul>
- *
- * <p>Supplying a schema with such changes will, by default, result in this call completing its
- * future with an {@link android.app.appsearch.exceptions.AppSearchException} with a code of
- * {@link AppSearchResult#RESULT_INVALID_SCHEMA} and a message describing the incompatibility.
- * In this case the previously set schema will remain active.
- *
- * <p>If you need to make non-backwards-compatible changes as described above, you can either:
- *
- * <ul>
- * <li>Set the {@link SetSchemaRequest.Builder#setForceOverride} method to {@code true}. In
- * this case, instead of completing its future with an {@link
- * android.app.appsearch.exceptions.AppSearchException} with the {@link
- * AppSearchResult#RESULT_INVALID_SCHEMA} error code, all documents which are not
- * compatible with the new schema will be deleted and the incompatible schema will be
- * applied. Incompatible types and deleted types will be set into {@link
- * SetSchemaResponse#getIncompatibleTypes()} and {@link
- * SetSchemaResponse#getDeletedTypes()}, respectively.
- * <li>Add a {@link android.app.appsearch.AppSearchSchema.Migrator} for each incompatible type
- * and make no deletion. The migrator will migrate documents from it's old schema version
- * to the new version. Migrated types will be set into both {@link
- * SetSchemaResponse#getIncompatibleTypes()} and {@link
- * SetSchemaResponse#getMigratedTypes()}. See the migration section below.
- * </ul>
- *
- * <p>It is a no-op to set the same schema as has been previously set; this is handled
- * efficiently.
- *
- * <p>By default, documents are visible on platform surfaces. To opt out, call
- * {@link SetSchemaRequest.Builder#setSchemaTypeVisibilityForSystemUi} with {@code visible} as
- * false. Any visibility settings apply only to the schemas that are included in the
- * {@code request}. Visibility settings for a schema type do not persist across
- * {@link #setSchema} calls.
- *
- * <p>Migration: make non-backwards-compatible changes will delete all stored documents in old
- * schema. You can save your documents by setting {@link
- * android.app.appsearch.AppSearchSchema.Migrator} via the {@link
- * SetSchemaRequest.Builder#setMigrator} for each type you want to save.
- *
- * <p>{@link android.app.appsearch.AppSearchSchema.Migrator#onDowngrade} or {@link
- * android.app.appsearch.AppSearchSchema.Migrator#onUpgrade} will be triggered if the version
- * number of the schema stored in AppSearch is different with the version in the request.
- *
- * <p>If any error or Exception occurred in the {@link
- * android.app.appsearch.AppSearchSchema.Migrator#onDowngrade}, {@link
- * android.app.appsearch.AppSearchSchema.Migrator#onUpgrade} or {@link
- * android.app.appsearch.AppSearchMigrationHelper.Transformer#transform}, the migration will be
- * terminated, the setSchema request will be rejected unless the schema changes are
- * backwards-compatible, and stored documents won't have any observable changes.
- *
- * @param request The schema update request.
- * @return A {@link ListenableFuture} with exception if we hit any error. Or the pending {@link
- * SetSchemaResponse} of performing this operation, if the schema has been successfully set.
- * @see android.app.appsearch.AppSearchSchema.Migrator
- * @see android.app.appsearch.AppSearchMigrationHelper.Transformer
+ * @param request the schema to set or update the AppSearch database to.
+ * @return a {@link ListenableFuture} which resolves to a {@link SetSchemaResponse} object.
*/
+ // TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are
+ // exposed.
@NonNull
ListenableFuture<SetSchemaResponse> setSchema(@NonNull SetSchemaRequest request);
@@ -132,15 +60,17 @@ public interface AppSearchSessionShim extends Closeable {
ListenableFuture<Set<AppSearchSchema>> getSchema();
/**
- * Indexes documents into AppSearch.
+ * Indexes documents into the {@link AppSearchSessionShim} database.
*
- * <p>Each {@link GenericDocument}'s {@code schemaType} field must be set to the name of a
- * schema type previously registered via the {@link #setSchema} method.
+ * <p>Each {@link GenericDocument} object must have a {@code schemaType} field set to an {@link
+ * AppSearchSchema} type that has been previously registered by calling the {@link #setSchema}
+ * method.
*
- * @param request {@link PutDocumentsRequest} containing documents to be indexed
- * @return The pending result of performing this operation. The keys of the returned {@link
- * AppSearchBatchResult} are the URIs of the input documents. The values are {@code null} if
- * they were successfully indexed, or a failed {@link AppSearchResult} otherwise.
+ * @param request containing documents to be indexed.
+ * @return a {@link ListenableFuture} which resolves to an {@link AppSearchBatchResult}. The
+ * keys of the returned {@link AppSearchBatchResult} are the URIs of the input documents.
+ * The values are either {@code null} if the corresponding document was successfully
+ * indexed, or a failed {@link AppSearchResult} otherwise.
*/
@NonNull
ListenableFuture<AppSearchBatchResult<String, Void>> put(@NonNull PutDocumentsRequest request);
@@ -213,7 +143,7 @@ public interface AppSearchSessionShim extends Closeable {
* adding projection, can be set by calling the corresponding {@link SearchSpec.Builder} setter.
*
* <p>This method is lightweight. The heavy work will be done in {@link
- * SearchResultsShim#getNextPage()}.
+ * SearchResultsShim#getNextPage}.
*
* @param queryExpression query string to search.
* @param searchSpec spec for setting document filters, adding projection, setting term match
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java
index 31c934f8bb27..d912c08e7d5f 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java
@@ -37,11 +37,11 @@ public interface GlobalSearchSessionShim extends Closeable {
* SetSchemaRequest.Builder#setSchemaTypeVisibilityForSystemUi}, or {@link
* SetSchemaRequest.Builder#setDocumentClassVisibilityForSystemUi} when building a schema.
*
- * <p>See {@link AppSearchSessionShim#search(String, SearchSpec)} for a detailed explanation on
- * forming a query string.
+ * <p>See {@link AppSearchSessionShim#search} for a detailed explanation on forming a query
+ * string.
*
* <p>This method is lightweight. The heavy work will be done in {@link
- * SearchResultsShim#getNextPage()}.
+ * SearchResultsShim#getNextPage}.
*
* @param queryExpression query string to search.
* @param searchSpec spec for setting document filters, adding projection, setting term match
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java
index 328c65ca2727..38f61f83d24e 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java
@@ -24,25 +24,29 @@ import java.io.Closeable;
import java.util.List;
/**
- * SearchResultsShim are a returned object from a query API.
+ * Encapsulates results of a search operation.
*
- * <p>Each {@link SearchResult} contains a document and may contain other fields like snippets based
- * on request.
+ * <p>Each {@link AppSearchSessionShim#search} operation returns a list of {@link SearchResult}
+ * objects, referred to as a "page", limited by the size configured by {@link
+ * SearchSpec.Builder#setResultCountPerPage}.
*
- * <p>Should close this object after finish fetching results.
+ * <p>To fetch a page of results, call {@link #getNextPage()}.
+ *
+ * <p>All instances of {@link SearchResultsShim} must call {@link SearchResultsShim#close()} after
+ * the results are fetched.
*
* <p>This class is not thread safe.
*/
public interface SearchResultsShim extends Closeable {
/**
- * Gets a whole page of {@link SearchResult}s.
+ * Retrieves the next page of {@link SearchResult} objects.
*
- * <p>Re-call this method to get next page of {@link SearchResult}, until it returns an empty
- * list.
+ * <p>The page size is configured by {@link SearchSpec.Builder#setResultCountPerPage}.
*
- * <p>The page size is set by {@link SearchSpec.Builder#setResultCountPerPage}.
+ * <p>Continue calling this method to access results until it returns an empty list, signifying
+ * there are no more results.
*
- * @return The pending result of performing this operation.
+ * @return a {@link ListenableFuture} which resolves to a list of {@link SearchResult} objects.
*/
@NonNull
ListenableFuture<List<SearchResult>> getNextPage();
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index 7c7b21001c3b..77146e0d1282 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -23,7 +23,7 @@ import android.annotation.SdkConstant;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.compat.annotation.ChangeId;
-import android.compat.annotation.Disabled;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
@@ -202,7 +202,7 @@ public class AlarmManager {
* @hide
*/
@ChangeId
- @Disabled // TODO (b/171306433): Enable starting S.
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
public static final long REQUIRE_EXACT_ALARM_PERMISSION = 171306433L;
@UnsupportedAppUsage
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 559a43491c7f..ea733696e1f7 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -423,6 +423,8 @@ public class AlarmManagerService extends SystemService {
static final String KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA = "allow_while_idle_compat_quota";
private static final String KEY_ALLOW_WHILE_IDLE_WINDOW = "allow_while_idle_window";
+ private static final String KEY_CRASH_NON_CLOCK_APPS = "crash_non_clock_apps";
+
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
private static final long DEFAULT_MAX_INTERVAL = 365 * DateUtils.DAY_IN_MILLIS;
@@ -454,6 +456,8 @@ public class AlarmManagerService extends SystemService {
private static final int DEFAULT_ALLOW_WHILE_IDLE_QUOTA = 72;
private static final long DEFAULT_ALLOW_WHILE_IDLE_WINDOW = 60 * 60 * 1000; // 1 hour.
+ // TODO (b/171306433): Change to true by default.
+ private static final boolean DEFAULT_CRASH_NON_CLOCK_APPS = false;
// Minimum futurity of a new alarm
public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
@@ -495,6 +499,13 @@ public class AlarmManagerService extends SystemService {
*/
public long ALLOW_WHILE_IDLE_WINDOW = DEFAULT_ALLOW_WHILE_IDLE_WINDOW;
+ /**
+ * Whether or not to crash callers that use setExactAndAllowWhileIdle or setAlarmClock
+ * but don't hold the required permission. This is useful to catch broken
+ * apps and reverting to a softer failure in case of broken apps.
+ */
+ public boolean CRASH_NON_CLOCK_APPS = DEFAULT_CRASH_NON_CLOCK_APPS;
+
private long mLastAllowWhileIdleWhitelistDuration = -1;
Constants() {
@@ -607,6 +618,10 @@ public class AlarmManagerService extends SystemService {
KEY_TIME_TICK_ALLOWED_WHILE_IDLE,
DEFAULT_TIME_TICK_ALLOWED_WHILE_IDLE);
break;
+ case KEY_CRASH_NON_CLOCK_APPS:
+ CRASH_NON_CLOCK_APPS = properties.getBoolean(KEY_CRASH_NON_CLOCK_APPS,
+ DEFAULT_CRASH_NON_CLOCK_APPS);
+ break;
default:
if (name.startsWith(KEY_PREFIX_STANDBY_QUOTA) && !standbyQuotaUpdated) {
// The quotas need to be updated in order, so we can't just rely
@@ -741,6 +756,9 @@ public class AlarmManagerService extends SystemService {
pw.print(KEY_TIME_TICK_ALLOWED_WHILE_IDLE, TIME_TICK_ALLOWED_WHILE_IDLE);
pw.println();
+ pw.print(KEY_CRASH_NON_CLOCK_APPS, CRASH_NON_CLOCK_APPS);
+ pw.println();
+
pw.decreaseIndent();
}
@@ -1914,11 +1932,12 @@ public class AlarmManagerService extends SystemService {
}
/**
- * Returns true if the given uid is on the system or user's power save exclusion list.
+ * Returns true if the given uid does not require SCHEDULE_EXACT_ALARM to set exact,
+ * allow-while-idle alarms.
*/
- boolean isWhitelisted(int uid) {
- return (mLocalDeviceIdleController == null || mLocalDeviceIdleController.isAppOnWhitelist(
- UserHandle.getAppId(uid)));
+ boolean isExemptFromPermission(int uid) {
+ return (UserHandle.isSameApp(mSystemUiUid, uid) || mLocalDeviceIdleController == null
+ || mLocalDeviceIdleController.isAppOnWhitelist(UserHandle.getAppId(uid)));
}
/**
@@ -1949,7 +1968,7 @@ public class AlarmManagerService extends SystemService {
if (windowLength != AlarmManager.WINDOW_EXACT) {
needsPermission = false;
lowQuota = true;
- idleOptions = isWhitelisted(callingUid) ? mOptsWithFgs.toBundle()
+ idleOptions = isExemptFromPermission(callingUid) ? mOptsWithFgs.toBundle()
: mOptsWithoutFgs.toBundle();
} else if (alarmClock != null) {
needsPermission = true;
@@ -1966,16 +1985,22 @@ public class AlarmManagerService extends SystemService {
idleOptions = allowWhileIdle ? mOptsWithFgs.toBundle() : null;
}
if (needsPermission && !canScheduleExactAlarms()) {
- if (alarmClock == null && isWhitelisted(callingUid)) {
+ if (alarmClock == null && isExemptFromPermission(callingUid)) {
// If the app is on the full system allow-list (not except-idle), we still
// allow the alarms, but with a lower quota to keep pre-S compatibility.
lowQuota = true;
} else {
- final String errorMessage = "Caller needs to hold "
+ final String errorMessage = "Caller " + callingPackage + " needs to hold "
+ Manifest.permission.SCHEDULE_EXACT_ALARM + " to set "
+ ((allowWhileIdle) ? "exact, allow-while-idle" : "alarm-clock")
+ " alarms.";
- throw new SecurityException(errorMessage);
+ if (mConstants.CRASH_NON_CLOCK_APPS) {
+ throw new SecurityException(errorMessage);
+ } else {
+ Slog.wtf(TAG, errorMessage);
+ idleOptions = mOptsWithoutFgs.toBundle();
+ lowQuota = allowWhileIdle;
+ }
}
}
if (lowQuota) {
@@ -2933,7 +2958,7 @@ public class AlarmManagerService extends SystemService {
if (UserHandle.isCore(uid) || uid == mSystemUiUid) {
return;
}
- if (isWhitelisted(uid)) {
+ if (isExemptFromPermission(uid)) {
return;
}
if (!CompatChanges.isChangeEnabled(
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index c5d3b7a726b9..fc2a409be2c2 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -53,7 +53,6 @@ import android.net.Uri;
import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
import android.os.Binder;
-import android.os.Build;
import android.os.Handler;
import android.os.LimitExceededException;
import android.os.Looper;
@@ -153,8 +152,7 @@ public class JobSchedulerService extends com.android.server.SystemService
/** The maximum number of jobs that we allow an unprivileged app to schedule */
private static final int MAX_JOBS_PER_APP = 100;
/** The number of the most recently completed jobs to keep track of for debugging purposes. */
- private static final int NUM_COMPLETED_JOB_HISTORY =
- Build.IS_USERDEBUG || Build.IS_ENG ? 25 : 0;
+ private static final int NUM_COMPLETED_JOB_HISTORY = 20;
@VisibleForTesting
public static Clock sSystemClock = Clock.systemUTC();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index be91947b0445..2a23d60d8af6 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -271,7 +271,9 @@ public final class JobServiceContext implements ServiceConnection {
if (job.shouldTreatAsExpeditedJob()) {
// TODO(171305774): The job should run on the little cores. We'll probably need
// another binding flag for that.
- bindFlags = Context.BIND_AUTO_CREATE;
+ bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
+ | Context.BIND_ALMOST_PERCEPTIBLE
+ | Context.BIND_ALLOW_NETWORK_ACCESS;
} else {
bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
| Context.BIND_NOT_PERCEPTIBLE;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 824fa7fc1659..2faa8360bf44 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -828,8 +828,8 @@ public final class QuotaController extends StateController {
}
@NonNull
- private ShrinkableDebits getEJQuotaLocked(final int userId,
- @NonNull final String packageName) {
+ @VisibleForTesting
+ ShrinkableDebits getEJDebitsLocked(final int userId, @NonNull final String packageName) {
ShrinkableDebits debits = mEJStats.get(userId, packageName);
if (debits == null) {
debits = new ShrinkableDebits(
@@ -931,7 +931,7 @@ public final class QuotaController extends StateController {
@VisibleForTesting
long getRemainingEJExecutionTimeLocked(final int userId, @NonNull final String packageName) {
- ShrinkableDebits quota = getEJQuotaLocked(userId, packageName);
+ ShrinkableDebits quota = getEJDebitsLocked(userId, packageName);
if (quota.getStandbyBucketLocked() == NEVER_INDEX) {
return 0;
}
@@ -948,7 +948,7 @@ public final class QuotaController extends StateController {
if (ts.endTimeElapsed < windowStartTimeElapsed) {
final long duration = ts.endTimeElapsed - ts.startTimeElapsed;
remainingMs += duration;
- quota.transactOnDebitsLocked(-duration);
+ quota.transactLocked(-duration);
timingSessions.remove(0);
} else if (ts.startTimeElapsed < windowStartTimeElapsed) {
remainingMs += windowStartTimeElapsed - ts.startTimeElapsed;
@@ -960,15 +960,16 @@ public final class QuotaController extends StateController {
}
}
+ TopAppTimer topAppTimer = mTopAppTrackers.get(userId, packageName);
+ if (topAppTimer != null && topAppTimer.isActive()) {
+ remainingMs += topAppTimer.getPendingReward(nowElapsed);
+ }
+
Timer timer = mEJPkgTimers.get(userId, packageName);
if (timer == null) {
return remainingMs;
}
- // There's a case where the debits tally is 0 but a currently running HPJ still counts
- // towards quota. If the app gets a reward in this case, the reward is lost and the HPJ
- // run is still fully counted.
- // TODO(171305774)/STOPSHIP: make sure getting rewards while HPJ currently executing isn't
- // treated negatively
+
return remainingMs - timer.getCurrentDuration(sElapsedRealtimeClock.millis());
}
@@ -1081,7 +1082,7 @@ public final class QuotaController extends StateController {
}
final long nowElapsed = sElapsedRealtimeClock.millis();
- ShrinkableDebits quota = getEJQuotaLocked(userId, packageName);
+ ShrinkableDebits quota = getEJDebitsLocked(userId, packageName);
final long limitMs = getEJLimitMsLocked(packageName, quota.getStandbyBucketLocked());
final long startWindowElapsed = Math.max(0, nowElapsed - mEJLimitWindowSizeMs);
long remainingDeadSpaceMs = remainingExecutionTimeMs;
@@ -1372,6 +1373,11 @@ public final class QuotaController extends StateController {
@VisibleForTesting
void saveTimingSession(final int userId, @NonNull final String packageName,
@NonNull final TimingSession session, boolean isExpedited) {
+ saveTimingSession(userId, packageName, session, isExpedited, 0);
+ }
+
+ private void saveTimingSession(final int userId, @NonNull final String packageName,
+ @NonNull final TimingSession session, boolean isExpedited, long debitAdjustment) {
synchronized (mLock) {
final SparseArrayMap<String, List<TimingSession>> sessionMap =
isExpedited ? mEJTimingSessions : mTimingSessions;
@@ -1382,8 +1388,9 @@ public final class QuotaController extends StateController {
}
sessions.add(session);
if (isExpedited) {
- final ShrinkableDebits quota = getEJQuotaLocked(userId, packageName);
- quota.transactOnDebitsLocked(session.endTimeElapsed - session.startTimeElapsed);
+ final ShrinkableDebits quota = getEJDebitsLocked(userId, packageName);
+ quota.transactLocked(session.endTimeElapsed - session.startTimeElapsed
+ + debitAdjustment);
} else {
// Adding a new session means that the current stats are now incorrect.
invalidateAllExecutionStatsLocked(userId, packageName);
@@ -1396,15 +1403,34 @@ public final class QuotaController extends StateController {
private void grantRewardForInstantEvent(
final int userId, @NonNull final String packageName, final long credit) {
synchronized (mLock) {
- final ShrinkableDebits quota = getEJQuotaLocked(userId, packageName);
- quota.transactOnDebitsLocked(-credit);
- if (maybeUpdateConstraintForPkgLocked(sElapsedRealtimeClock.millis(),
- userId, packageName)) {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ final ShrinkableDebits quota = getEJDebitsLocked(userId, packageName);
+ if (transactQuotaLocked(userId, packageName, nowElapsed, quota, credit)
+ && maybeUpdateConstraintForPkgLocked(nowElapsed, userId, packageName)) {
mStateChangedListener.onControllerStateChanged();
}
}
}
+ private boolean transactQuotaLocked(final int userId, @NonNull final String packageName,
+ final long nowElapsed, @NonNull ShrinkableDebits debits, final long credit) {
+ final long oldTally = debits.getTallyLocked();
+ final long leftover = debits.transactLocked(-credit);
+ if (DEBUG) {
+ Slog.d(TAG, "debits overflowed by " + leftover);
+ }
+ boolean changed = oldTally != debits.getTallyLocked();
+ if (leftover != 0) {
+ // Only adjust timer if its active.
+ final Timer ejTimer = mEJPkgTimers.get(userId, packageName);
+ if (ejTimer != null && ejTimer.isActive()) {
+ ejTimer.updateDebitAdjustment(nowElapsed, leftover);
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
private final class EarliestEndTimeFunctor implements Consumer<List<TimingSession>> {
public long earliestEndElapsed = Long.MAX_VALUE;
@@ -1875,7 +1901,8 @@ public final class QuotaController extends StateController {
}
}
- private static final class ShrinkableDebits {
+ @VisibleForTesting
+ static final class ShrinkableDebits {
/** The amount of quota remaining. Can be negative if limit changes. */
private long mDebitTally;
private int mStandbyBucket;
@@ -1893,8 +1920,11 @@ public final class QuotaController extends StateController {
* Negative if the tally should decrease (therefore increasing available quota);
* or positive if the tally should increase (therefore decreasing available quota).
*/
- void transactOnDebitsLocked(final long amount) {
+ long transactLocked(final long amount) {
+ final long leftover = amount < 0 && Math.abs(amount) > mDebitTally
+ ? mDebitTally + amount : 0;
mDebitTally = Math.max(0, mDebitTally + amount);
+ return leftover;
}
void setStandbyBucketLocked(int standbyBucket) {
@@ -1927,6 +1957,7 @@ public final class QuotaController extends StateController {
private final ArraySet<JobStatus> mRunningBgJobs = new ArraySet<>();
private long mStartTimeElapsed;
private int mBgJobCount;
+ private long mDebitAdjustment;
Timer(int uid, int userId, String packageName, boolean regularJobTimer) {
mPkg = new Package(userId, packageName);
@@ -1957,6 +1988,7 @@ public final class QuotaController extends StateController {
if (mRunningBgJobs.size() == 1) {
// Started tracking the first job.
mStartTimeElapsed = sElapsedRealtimeClock.millis();
+ mDebitAdjustment = 0;
if (mRegularJobTimer) {
// Starting the timer means that all cached execution stats are now
// incorrect.
@@ -1988,6 +2020,11 @@ public final class QuotaController extends StateController {
}
}
+ void updateDebitAdjustment(long nowElapsed, long debit) {
+ // Make sure we don't have a credit larger than the expected session.
+ mDebitAdjustment = Math.max(mDebitAdjustment + debit, mStartTimeElapsed - nowElapsed);
+ }
+
/**
* Stops tracking all jobs and cancels any pending alarms. This should only be called if
* the Timer is not going to be used anymore.
@@ -2003,7 +2040,8 @@ public final class QuotaController extends StateController {
return;
}
TimingSession ts = new TimingSession(mStartTimeElapsed, nowElapsed, mBgJobCount);
- saveTimingSession(mPkg.userId, mPkg.packageName, ts, !mRegularJobTimer);
+ saveTimingSession(mPkg.userId, mPkg.packageName, ts, !mRegularJobTimer,
+ mDebitAdjustment);
mBgJobCount = 0;
// Don't reset the tracked jobs list as we need to keep tracking the current number
// of jobs.
@@ -2030,7 +2068,7 @@ public final class QuotaController extends StateController {
long getCurrentDuration(long nowElapsed) {
synchronized (mLock) {
- return !isActive() ? 0 : nowElapsed - mStartTimeElapsed;
+ return !isActive() ? 0 : nowElapsed - mStartTimeElapsed + mDebitAdjustment;
}
}
@@ -2059,6 +2097,7 @@ public final class QuotaController extends StateController {
// Start timing from unplug.
if (mRunningBgJobs.size() > 0) {
mStartTimeElapsed = nowElapsed;
+ mDebitAdjustment = 0;
// NOTE: this does have the unfortunate consequence that if the device is
// repeatedly plugged in and unplugged, or an app changes foreground state
// very frequently, the job count for a package may be artificially high.
@@ -2128,6 +2167,11 @@ public final class QuotaController extends StateController {
pw.print(", ");
pw.print(mBgJobCount);
pw.print(" running bg jobs");
+ if (!mRegularJobTimer) {
+ pw.print(" (debit adj=");
+ pw.print(mDebitAdjustment);
+ pw.print(")");
+ }
pw.println();
pw.increaseIndent();
for (int i = 0; i < mRunningBgJobs.size(); i++) {
@@ -2171,6 +2215,21 @@ public final class QuotaController extends StateController {
mPkg = new Package(userId, packageName);
}
+ private int calculateTimeChunks(final long nowElapsed) {
+ final long totalTopTimeMs = nowElapsed - mStartTimeElapsed;
+ int numTimeChunks = (int) (totalTopTimeMs / mEJTopAppTimeChunkSizeMs);
+ final long remainderMs = totalTopTimeMs % mEJTopAppTimeChunkSizeMs;
+ if (remainderMs >= SECOND_IN_MILLIS) {
+ // "Round up"
+ numTimeChunks++;
+ }
+ return numTimeChunks;
+ }
+
+ long getPendingReward(final long nowElapsed) {
+ return mEJRewardTopAppMs * calculateTimeChunks(nowElapsed);
+ }
+
void processEventLocked(@NonNull UsageEvents.Event event) {
final long nowElapsed = sElapsedRealtimeClock.millis();
switch (event.getEventType()) {
@@ -2186,21 +2245,16 @@ public final class QuotaController extends StateController {
final UsageEvents.Event existingEvent =
mActivities.removeReturnOld(event.mInstanceId);
if (existingEvent != null && mActivities.size() == 0) {
- final long totalTopTimeMs = nowElapsed - mStartTimeElapsed;
- int numTimeChunks = (int) (totalTopTimeMs / mEJTopAppTimeChunkSizeMs);
- final long remainderMs = totalTopTimeMs % mEJTopAppTimeChunkSizeMs;
- if (remainderMs >= SECOND_IN_MILLIS) {
- // "Round up"
- numTimeChunks++;
- }
+ final long pendingReward = getPendingReward(nowElapsed);
if (DEBUG) {
- Slog.d(TAG,
- "Crediting " + mPkg + " for " + numTimeChunks + " time chunks");
+ Slog.d(TAG, "Crediting " + mPkg + " " + pendingReward + "ms"
+ + " for " + calculateTimeChunks(nowElapsed) + " time chunks");
}
- final ShrinkableDebits quota =
- getEJQuotaLocked(mPkg.userId, mPkg.packageName);
- quota.transactOnDebitsLocked(-mEJRewardTopAppMs * numTimeChunks);
- if (maybeUpdateConstraintForPkgLocked(nowElapsed,
+ final ShrinkableDebits debits =
+ getEJDebitsLocked(mPkg.userId, mPkg.packageName);
+ if (transactQuotaLocked(mPkg.userId, mPkg.packageName,
+ nowElapsed, debits, pendingReward)
+ && maybeUpdateConstraintForPkgLocked(nowElapsed,
mPkg.userId, mPkg.packageName)) {
mStateChangedListener.onControllerStateChanged();
}
@@ -2321,7 +2375,7 @@ public final class QuotaController extends StateController {
*/
@Override
public void onUsageEvent(int userId, @NonNull UsageEvents.Event event) {
- mHandler.obtainMessage(MSG_PROCESS_USAGE_EVENT, userId, 0, event);
+ mHandler.obtainMessage(MSG_PROCESS_USAGE_EVENT, userId, 0, event).sendToTarget();
}
}
@@ -2408,7 +2462,6 @@ public final class QuotaController extends StateController {
}
private class QcHandler extends Handler {
- private boolean mIsProcessing;
QcHandler(Looper looper) {
super(looper);
@@ -2417,8 +2470,6 @@ public final class QuotaController extends StateController {
@Override
public void handleMessage(Message msg) {
synchronized (mLock) {
- mIsProcessing = true;
-
switch (msg.what) {
case MSG_REACHED_QUOTA: {
Package pkg = (Package) msg.obj;
@@ -2539,6 +2590,10 @@ public final class QuotaController extends StateController {
final int userId = msg.arg1;
final UsageEvents.Event event = (UsageEvents.Event) msg.obj;
final String pkgName = event.getPackageName();
+ if (DEBUG) {
+ Slog.d(TAG, "Processing event " + event.getEventType()
+ + " for " + string(userId, pkgName));
+ }
switch (event.getEventType()) {
case UsageEvents.Event.ACTIVITY_RESUMED:
case UsageEvents.Event.ACTIVITY_PAUSED:
@@ -2604,8 +2659,6 @@ public final class QuotaController extends StateController {
}
}
}
-
- mIsProcessing = false;
}
}
@@ -3883,11 +3936,6 @@ public final class QuotaController extends StateController {
return mQcConstants;
}
- @VisibleForTesting
- boolean isActiveBackgroundProcessing() {
- return mHandler.mIsProcessing;
- }
-
//////////////////////////// DATA DUMP //////////////////////////////
@Override
diff --git a/apex/jobscheduler/service/jni/Android.bp b/apex/jobscheduler/service/jni/Android.bp
index 4bcc165e9eea..c630217387ce 100644
--- a/apex/jobscheduler/service/jni/Android.bp
+++ b/apex/jobscheduler/service/jni/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
cc_library_shared {
name: "libalarm_jni",
diff --git a/apex/media/service/Android.bp b/apex/media/service/Android.bp
index 5b24cfa4219b..9b3399e8b0e1 100644
--- a/apex/media/service/Android.bp
+++ b/apex/media/service/Android.bp
@@ -11,6 +11,15 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
filegroup {
name: "service-media-s-sources",
srcs: [
@@ -38,4 +47,3 @@ java_sdk_library {
"com.android.media",
],
}
-
diff --git a/cmds/abx/Android.bp b/cmds/abx/Android.bp
index 333acedfadad..50a0b75b3276 100644
--- a/cmds/abx/Android.bp
+++ b/cmds/abx/Android.bp
@@ -1,4 +1,21 @@
+package {
+ default_applicable_licenses: ["frameworks_base_cmds_abx_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_base_cmds_abx_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
java_binary {
name: "abx",
wrapper: "abx",
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 4b7eda096e54..ed717c491467 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -19,7 +19,6 @@ package com.android.commands.bmgr;
import android.annotation.IntDef;
import android.annotation.UserIdInt;
import android.app.backup.BackupManager;
-import android.app.backup.BackupManager.OperationType;
import android.app.backup.BackupManagerMonitor;
import android.app.backup.BackupProgress;
import android.app.backup.BackupTransport;
@@ -667,7 +666,7 @@ public class Bmgr {
// The rest of the 'list' options work with a restore session on the current transport
try {
- mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null, OperationType.BACKUP);
+ mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null);
if (mRestore == null) {
System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId);
return;
@@ -822,7 +821,7 @@ public class Bmgr {
try {
boolean didRestore = false;
- mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null, OperationType.BACKUP);
+ mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null);
if (mRestore == null) {
System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId);
return;
diff --git a/cmds/hid/OWNERS b/cmds/hid/OWNERS
new file mode 100644
index 000000000000..d701f23cb9b8
--- /dev/null
+++ b/cmds/hid/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/hardware/input/OWNERS
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
index 437a87e8df54..2cda57dd67e9 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.cpp
+++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
@@ -48,6 +48,7 @@ static const char* UHID_PATH = "/dev/uhid";
static struct {
jmethodID onDeviceOpen;
jmethodID onDeviceGetReport;
+ jmethodID onDeviceSetReport;
jmethodID onDeviceOutput;
jmethodID onDeviceError;
} gDeviceCallbackClassInfo;
@@ -113,7 +114,16 @@ void DeviceCallback::onDeviceGetReport(uint32_t requestId, uint8_t reportId) {
checkAndClearException(env, "onDeviceGetReport");
}
-void DeviceCallback::onDeviceOutput(uint8_t rType, const std::vector<uint8_t>& data) {
+void DeviceCallback::onDeviceSetReport(uint8_t rType,
+ const std::vector<uint8_t>& data) {
+ JNIEnv* env = getJNIEnv();
+ env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceSetReport, rType,
+ toJbyteArray(env, data).get());
+ checkAndClearException(env, "onDeviceSetReport");
+}
+
+void DeviceCallback::onDeviceOutput(uint8_t rType,
+ const std::vector<uint8_t>& data) {
JNIEnv* env = getJNIEnv();
env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOutput, rType,
toJbyteArray(env, data).get());
@@ -261,6 +271,7 @@ int Device::handleEvents(int events) {
ALOGD("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id,
set_report.rnum, toString(data).c_str());
}
+ mDeviceCallback->onDeviceSetReport(set_report.rtype, data);
break;
}
case UHID_OUTPUT: {
@@ -364,6 +375,8 @@ int register_com_android_commands_hid_Device(JNIEnv* env) {
env->GetMethodID(clazz, "onDeviceOpen", "()V");
uhid::gDeviceCallbackClassInfo.onDeviceGetReport =
env->GetMethodID(clazz, "onDeviceGetReport", "(II)V");
+ uhid::gDeviceCallbackClassInfo.onDeviceSetReport =
+ env->GetMethodID(clazz, "onDeviceSetReport", "(B[B)V");
uhid::gDeviceCallbackClassInfo.onDeviceOutput =
env->GetMethodID(clazz, "onDeviceOutput", "(B[B)V");
uhid::gDeviceCallbackClassInfo.onDeviceError =
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h
index 5483b40831a0..d10a9aa3680c 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.h
+++ b/cmds/hid/jni/com_android_commands_hid_Device.h
@@ -31,6 +31,7 @@ public:
void onDeviceOpen();
void onDeviceGetReport(uint32_t requestId, uint8_t reportId);
+ void onDeviceSetReport(uint8_t rType, const std::vector<uint8_t>& data);
void onDeviceOutput(uint8_t rType, const std::vector<uint8_t>& data);
void onDeviceError();
diff --git a/cmds/hid/src/com/android/commands/hid/Device.java b/cmds/hid/src/com/android/commands/hid/Device.java
index 20b4bd86baec..95b1e9a7b57f 100644
--- a/cmds/hid/src/com/android/commands/hid/Device.java
+++ b/cmds/hid/src/com/android/commands/hid/Device.java
@@ -46,7 +46,8 @@ public class Device {
// Sync with linux uhid_event_type::UHID_OUTPUT
private static final byte UHID_EVENT_TYPE_UHID_OUTPUT = 6;
-
+ // Sync with linux uhid_event_type::UHID_SET_REPORT
+ private static final byte UHID_EVENT_TYPE_SET_REPORT = 13;
private final int mId;
private final HandlerThread mThread;
private final DeviceHandler mHandler;
@@ -198,11 +199,11 @@ public class Device {
mHandler.sendMessageAtTime(msg, mTimeToSend);
}
- // native callback
- public void onDeviceOutput(byte rtype, byte[] data) {
+ // Send out the report to HID command output
+ private void sendReportOutput(byte eventId, byte rtype, byte[] data) {
JSONObject json = new JSONObject();
try {
- json.put("eventId", UHID_EVENT_TYPE_UHID_OUTPUT);
+ json.put("eventId", eventId);
json.put("deviceId", mId);
json.put("reportType", rtype);
JSONArray dataArray = new JSONArray();
@@ -220,6 +221,18 @@ public class Device {
throw new RuntimeException(e);
}
+ }
+
+ // native callback
+ public void onDeviceSetReport(byte rtype, byte[] data) {
+ // We don't need to reply for the SET_REPORT but just send it to HID output for test
+ // verification.
+ sendReportOutput(UHID_EVENT_TYPE_SET_REPORT, rtype, data);
+ }
+
+ // native callback
+ public void onDeviceOutput(byte rtype, byte[] data) {
+ sendReportOutput(UHID_EVENT_TYPE_UHID_OUTPUT, rtype, data);
if (mOutputs == null) {
Log.e(TAG, "Received OUTPUT request, but 'outputs' section is not found");
return;
diff --git a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
index a0361d0a39d3..ca9df39f83bf 100644
--- a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
+++ b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
@@ -182,6 +182,8 @@ public class RequestSync {
mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
} else if (opt.equals("--rc") || opt.equals("--require-charging")) {
mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING, true);
+ } else if (opt.equals("--ej") || opt.equals("--schedule-as-ej")) {
+ mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, true);
} else if (opt.equals("-e") || opt.equals("--es") || opt.equals("--extra-string")) {
final String key = nextArgRequired();
final String value = nextArgRequired();
diff --git a/cmds/uinput/Android.bp b/cmds/uinput/Android.bp
index 0d7fed2a15c7..260cfc781ebc 100644
--- a/cmds/uinput/Android.bp
+++ b/cmds/uinput/Android.bp
@@ -1,6 +1,23 @@
// Copyright 2020 The Android Open Source Project
//
+package {
+ default_applicable_licenses: ["frameworks_base_cmds_uinput_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_base_cmds_uinput_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
java_binary {
name: "uinput",
wrapper: "uinput",
@@ -15,4 +32,4 @@ filegroup {
srcs: [
"src/com/android/commands/uinput/InputAbsInfo.aidl",
],
-} \ No newline at end of file
+}
diff --git a/cmds/uinput/jni/Android.bp b/cmds/uinput/jni/Android.bp
index 199bbbd35274..c56adc35b580 100644
--- a/cmds/uinput/jni/Android.bp
+++ b/cmds/uinput/jni/Android.bp
@@ -1,3 +1,12 @@
+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_cmds_uinput_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_cmds_uinput_license"],
+}
+
cc_library_shared {
name: "libuinputcommand_jni",
diff --git a/core/api/current.txt b/core/api/current.txt
index b0375b69553d..08c7a43294c3 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -507,6 +507,7 @@ package android {
field public static final int dashGap = 16843175; // 0x10101a7
field public static final int dashWidth = 16843174; // 0x10101a6
field public static final int data = 16842798; // 0x101002e
+ field public static final int dataExtractionRules = 16844350; // 0x101063e
field public static final int datePickerDialogTheme = 16843948; // 0x10104ac
field public static final int datePickerMode = 16843955; // 0x10104b3
field public static final int datePickerStyle = 16843612; // 0x101035c
@@ -528,6 +529,8 @@ package android {
field public static final int detailSocialSummary = 16843428; // 0x10102a4
field public static final int detailsElementBackground = 16843598; // 0x101034e
field public static final int dial = 16843010; // 0x1010102
+ field public static final int dialTint = 16844342; // 0x1010636
+ field public static final int dialTintMode = 16844343; // 0x1010637
field public static final int dialogCornerRadius = 16844145; // 0x1010571
field public static final int dialogIcon = 16843252; // 0x10101f4
field public static final int dialogLayout = 16843255; // 0x10101f7
@@ -725,8 +728,14 @@ package android {
field public static final int groupIndicator = 16843019; // 0x101010b
field public static final int gwpAsanMode = 16844310; // 0x1010616
field public static final int hand_hour = 16843011; // 0x1010103
+ field public static final int hand_hourTint = 16844344; // 0x1010638
+ field public static final int hand_hourTintMode = 16844345; // 0x1010639
field public static final int hand_minute = 16843012; // 0x1010104
+ field public static final int hand_minuteTint = 16844346; // 0x101063a
+ field public static final int hand_minuteTintMode = 16844347; // 0x101063b
field public static final int hand_second = 16844323; // 0x1010623
+ field public static final int hand_secondTint = 16844348; // 0x101063c
+ field public static final int hand_secondTintMode = 16844349; // 0x101063d
field public static final int handle = 16843354; // 0x101025a
field public static final int handleProfiling = 16842786; // 0x1010022
field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e
@@ -4735,6 +4744,13 @@ package android.app {
field @NonNull public static final android.os.Parcelable.Creator<android.app.AutomaticZenRule> CREATOR;
}
+ public final class BackgroundServiceStartNotAllowedException extends android.app.ServiceStartNotAllowedException implements android.os.Parcelable {
+ ctor public BackgroundServiceStartNotAllowedException(@NonNull String);
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.BackgroundServiceStartNotAllowedException> CREATOR;
+ }
+
public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
ctor public DatePickerDialog(@NonNull android.content.Context);
ctor public DatePickerDialog(@NonNull android.content.Context, @StyleRes int);
@@ -4980,6 +4996,13 @@ package android.app {
method @Deprecated public void setSelectedGroup(int);
}
+ public final class ForegroundServiceStartNotAllowedException extends android.app.ServiceStartNotAllowedException implements android.os.Parcelable {
+ ctor public ForegroundServiceStartNotAllowedException(@NonNull String);
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.ForegroundServiceStartNotAllowedException> CREATOR;
+ }
+
@Deprecated public class Fragment implements android.content.ComponentCallbacks2 android.view.View.OnCreateContextMenuListener {
ctor @Deprecated public Fragment();
method @Deprecated public void dump(String, java.io.FileDescriptor, java.io.PrintWriter, String[]);
@@ -5588,6 +5611,7 @@ package android.app {
field public static final int DEFAULT_LIGHTS = 4; // 0x4
field public static final int DEFAULT_SOUND = 1; // 0x1
field public static final int DEFAULT_VIBRATE = 2; // 0x2
+ field public static final String EXTRA_ANSWER_COLOR = "android.answerColor";
field public static final String EXTRA_ANSWER_INTENT = "android.answerIntent";
field public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
field public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
@@ -5599,6 +5623,7 @@ package android.app {
field public static final String EXTRA_COLORIZED = "android.colorized";
field public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
field public static final String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+ field public static final String EXTRA_DECLINE_COLOR = "android.declineColor";
field public static final String EXTRA_DECLINE_INTENT = "android.declineIntent";
field public static final String EXTRA_HANG_UP_INTENT = "android.hangUpIntent";
field public static final String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
@@ -5886,6 +5911,8 @@ package android.app {
method @NonNull public static android.app.Notification.CallStyle forIncomingCall(@NonNull android.app.Person, @NonNull android.app.PendingIntent, @NonNull android.app.PendingIntent);
method @NonNull public static android.app.Notification.CallStyle forOngoingCall(@NonNull android.app.Person, @NonNull android.app.PendingIntent);
method @NonNull public static android.app.Notification.CallStyle forScreeningCall(@NonNull android.app.Person, @NonNull android.app.PendingIntent, @NonNull android.app.PendingIntent);
+ method @NonNull public android.app.Notification.CallStyle setAnswerButtonColorHint(@ColorInt int);
+ method @NonNull public android.app.Notification.CallStyle setDeclineButtonColorHint(@ColorInt int);
method @NonNull public android.app.Notification.CallStyle setVerificationIcon(@Nullable android.graphics.drawable.Icon);
method @NonNull public android.app.Notification.CallStyle setVerificationText(@Nullable CharSequence);
}
@@ -6563,6 +6590,9 @@ package android.app {
field public static final int STOP_FOREGROUND_REMOVE = 1; // 0x1
}
+ public abstract class ServiceStartNotAllowedException extends java.lang.IllegalStateException {
+ }
+
public abstract class SharedElementCallback {
ctor public SharedElementCallback();
method public android.os.Parcelable onCaptureSharedElementSnapshot(android.view.View, android.graphics.Matrix, android.graphics.RectF);
@@ -8346,7 +8376,9 @@ package android.appwidget {
method protected android.view.View getDefaultView();
method protected android.view.View getErrorView();
method protected void prepareView(android.view.View);
+ method public void resetColorResources();
method public void setAppWidget(int, android.appwidget.AppWidgetProviderInfo);
+ method public void setColorResources(@NonNull android.util.SparseIntArray);
method public void setCurrentSize(@NonNull android.graphics.PointF);
method public void setExecutor(java.util.concurrent.Executor);
method public void setOnLightBackground(boolean);
@@ -8427,7 +8459,7 @@ package android.appwidget {
method public int describeContents();
method public final android.os.UserHandle getProfile();
method @NonNull public android.content.pm.ActivityInfo getProviderInfo();
- method @Nullable public final String loadDescription(@NonNull android.content.Context);
+ method @Nullable public final CharSequence loadDescription(@NonNull android.content.Context);
method public final android.graphics.drawable.Drawable loadIcon(@NonNull android.content.Context, int);
method public final String loadLabel(android.content.pm.PackageManager);
method public final android.graphics.drawable.Drawable loadPreviewImage(@NonNull android.content.Context, int);
@@ -8445,7 +8477,7 @@ package android.appwidget {
field public static final int WIDGET_FEATURE_RECONFIGURABLE = 1; // 0x1
field public int autoAdvanceViewId;
field public android.content.ComponentName configure;
- field @IdRes public int descriptionResource;
+ field @IdRes public int descriptionRes;
field public int icon;
field public int initialKeyguardLayout;
field public int initialLayout;
@@ -10213,6 +10245,7 @@ package android.content {
field public static final String SYNC_EXTRAS_MANUAL = "force";
field public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
field public static final String SYNC_EXTRAS_REQUIRE_CHARGING = "require_charging";
+ field public static final String SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB = "schedule_as_expedited_job";
field public static final String SYNC_EXTRAS_UPLOAD = "upload";
field public static final int SYNC_OBSERVER_TYPE_ACTIVE = 4; // 0x4
field public static final int SYNC_OBSERVER_TYPE_PENDING = 2; // 0x2
@@ -10356,7 +10389,7 @@ package android.content {
method public abstract void grantUriPermission(String, android.net.Uri, int);
method public abstract boolean isDeviceProtectedStorage();
method public boolean isRestricted();
- method public static boolean isUiContext(@NonNull android.content.Context);
+ method public boolean isUiContext();
method public abstract boolean moveDatabaseFrom(android.content.Context, String);
method public abstract boolean moveSharedPreferencesFrom(android.content.Context, String);
method @NonNull public final android.content.res.TypedArray obtainStyledAttributes(@NonNull @StyleableRes int[]);
@@ -11535,6 +11568,7 @@ package android.content {
method public android.content.SyncRequest.Builder setManual(boolean);
method public android.content.SyncRequest.Builder setNoRetry(boolean);
method public android.content.SyncRequest.Builder setRequiresCharging(boolean);
+ method @NonNull public android.content.SyncRequest.Builder setScheduleAsExpeditedJob(boolean);
method public android.content.SyncRequest.Builder setSyncAdapter(android.accounts.Account, String);
method public android.content.SyncRequest.Builder syncOnce();
method public android.content.SyncRequest.Builder syncPeriodic(long, long);
@@ -18534,23 +18568,6 @@ package android.hardware.camera2.params {
package android.hardware.display {
- public final class DeviceProductInfo implements android.os.Parcelable {
- method public int describeContents();
- method public int getConnectionToSinkType();
- method public int getManufactureWeek();
- method public int getManufactureYear();
- method @NonNull public String getManufacturerPnpId();
- method public int getModelYear();
- method @Nullable public String getName();
- method @NonNull public String getProductId();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final int CONNECTION_TO_SINK_BUILT_IN = 1; // 0x1
- field public static final int CONNECTION_TO_SINK_DIRECT = 2; // 0x2
- field public static final int CONNECTION_TO_SINK_TRANSITIVE = 3; // 0x3
- field public static final int CONNECTION_TO_SINK_UNKNOWN = 0; // 0x0
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.display.DeviceProductInfo> CREATOR;
- }
-
public final class DisplayManager {
method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int);
method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int, @Nullable android.hardware.display.VirtualDisplay.Callback, @Nullable android.os.Handler);
@@ -18659,6 +18676,58 @@ package android.hardware.input {
}
+package android.hardware.lights {
+
+ public final class Light implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getId();
+ method @NonNull public String getName();
+ method public int getOrdinal();
+ method public int getType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.Light> CREATOR;
+ field public static final int LIGHT_TYPE_INPUT_PLAYER_ID = 10; // 0xa
+ field public static final int LIGHT_TYPE_INPUT_RGB = 11; // 0xb
+ field public static final int LIGHT_TYPE_INPUT_SINGLE = 9; // 0x9
+ field public static final int LIGHT_TYPE_MICROPHONE = 8; // 0x8
+ }
+
+ public final class LightState implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public static android.hardware.lights.LightState forColor(@ColorInt int);
+ method @NonNull public static android.hardware.lights.LightState forPlayerId(int);
+ method @ColorInt public int getColor();
+ method public int getPlayerId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.LightState> CREATOR;
+ }
+
+ public abstract class LightsManager {
+ method @NonNull public abstract android.hardware.lights.LightState getLightState(@NonNull android.hardware.lights.Light);
+ method @NonNull public abstract java.util.List<android.hardware.lights.Light> getLights();
+ method @NonNull public abstract android.hardware.lights.LightsManager.LightsSession openSession();
+ }
+
+ public abstract static class LightsManager.LightsSession implements java.lang.AutoCloseable {
+ ctor public LightsManager.LightsSession();
+ method public abstract void close();
+ method public abstract void requestLights(@NonNull android.hardware.lights.LightsRequest);
+ }
+
+ public final class LightsRequest {
+ method @NonNull public java.util.List<android.hardware.lights.LightState> getLightStates();
+ method @NonNull public java.util.List<java.lang.Integer> getLights();
+ }
+
+ public static final class LightsRequest.Builder {
+ ctor public LightsRequest.Builder();
+ method @NonNull public android.hardware.lights.LightsRequest.Builder addLight(@NonNull android.hardware.lights.Light, @NonNull android.hardware.lights.LightState);
+ method @NonNull public android.hardware.lights.LightsRequest build();
+ method @NonNull public android.hardware.lights.LightsRequest.Builder clearLight(@NonNull android.hardware.lights.Light);
+ }
+
+}
+
package android.hardware.usb {
public class UsbAccessory implements android.os.Parcelable {
@@ -18827,6 +18896,7 @@ package android.inputmethodservice {
public abstract class AbstractInputMethodService extends android.app.Service implements android.view.KeyEvent.Callback {
ctor public AbstractInputMethodService();
method public android.view.KeyEvent.DispatcherState getKeyDispatcherState();
+ method public final boolean isUiContext();
method public final android.os.IBinder onBind(android.content.Intent);
method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl onCreateInputMethodInterface();
method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
@@ -26219,6 +26289,7 @@ package android.net {
field public static final int NET_CAPABILITY_CBS = 5; // 0x5
field public static final int NET_CAPABILITY_DUN = 2; // 0x2
field public static final int NET_CAPABILITY_EIMS = 10; // 0xa
+ field public static final int NET_CAPABILITY_ENTERPRISE = 29; // 0x1d
field public static final int NET_CAPABILITY_FOREGROUND = 19; // 0x13
field public static final int NET_CAPABILITY_FOTA = 3; // 0x3
field public static final int NET_CAPABILITY_IA = 7; // 0x7
@@ -30586,8 +30657,8 @@ package android.os {
}
public final class BugreportManager {
- method public void cancelBugreport();
- method public void startConnectivityBugreport(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
+ method @WorkerThread public void cancelBugreport();
+ method @WorkerThread public void startConnectivityBugreport(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
}
public abstract static class BugreportManager.BugreportCallback {
@@ -35049,6 +35120,7 @@ package android.provider {
field public static final String ACTION_QUICK_ACCESS_WALLET_SETTINGS = "android.settings.QUICK_ACCESS_WALLET_SETTINGS";
field public static final String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
field public static final String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
+ field public static final String ACTION_REQUEST_SCHEDULE_EXACT_ALARM = "android.settings.REQUEST_SCHEDULE_EXACT_ALARM";
field public static final String ACTION_REQUEST_SET_AUTOFILL_SERVICE = "android.settings.REQUEST_SET_AUTOFILL_SERVICE";
field public static final String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
@@ -37093,8 +37165,10 @@ package android.security {
method @NonNull public static android.content.Intent createInstallIntent();
method @NonNull public static android.content.Intent createManageCredentialsIntent(@NonNull android.security.AppUriAuthenticationPolicy);
method @Nullable @WorkerThread public static java.security.cert.X509Certificate[] getCertificateChain(@NonNull android.content.Context, @NonNull String) throws java.lang.InterruptedException, android.security.KeyChainException;
+ method @NonNull public static android.security.AppUriAuthenticationPolicy getCredentialManagementAppPolicy(@NonNull android.content.Context) throws java.lang.SecurityException;
method @Nullable @WorkerThread public static java.security.PrivateKey getPrivateKey(@NonNull android.content.Context, @NonNull String) throws java.lang.InterruptedException, android.security.KeyChainException;
method @Deprecated public static boolean isBoundKeyAlgorithm(@NonNull String);
+ method public static boolean isCredentialManagementApp(@NonNull android.content.Context);
method public static boolean isKeyAlgorithmSupported(@NonNull String);
field public static final String ACTION_KEYCHAIN_CHANGED = "android.security.action.KEYCHAIN_CHANGED";
field public static final String ACTION_KEY_ACCESS_CHANGED = "android.security.action.KEY_ACCESS_CHANGED";
@@ -41165,6 +41239,7 @@ package android.telephony {
field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e
field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f
field public static final int ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED = 65; // 0x41
+ field public static final int ALL_MATCHING_RULES_FAILED = 2254; // 0x8ce
field public static final int APN_DISABLED = 2045; // 0x7fd
field public static final int APN_DISALLOWED_ON_ROAMING = 2059; // 0x80b
field public static final int APN_MISMATCH = 2054; // 0x806
@@ -41314,6 +41389,7 @@ package android.telephony {
field public static final int LTE_NAS_SERVICE_REQUEST_FAILED = 2117; // 0x845
field public static final int LTE_THROTTLING_NOT_REQUIRED = 2127; // 0x84f
field public static final int MAC_FAILURE = 2183; // 0x887
+ field public static final int MATCH_ALL_RULE_NOT_ALLOWED = 2253; // 0x8cd
field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d
field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876
field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f
@@ -42099,6 +42175,7 @@ package android.telephony {
method @NonNull public android.telephony.SmsManager createForSubscriptionId(int);
method public java.util.ArrayList<java.lang.String> divideMessage(String);
method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
+ method public void downloadMultimediaMessage(@NonNull android.content.Context, @NonNull String, @NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent, long);
method @NonNull public android.os.Bundle getCarrierConfigValues();
method @Deprecated public static android.telephony.SmsManager getDefault();
method public static int getDefaultSmsSubscriptionId();
@@ -42110,6 +42187,7 @@ package android.telephony {
method public void injectSmsPdu(byte[], String, android.app.PendingIntent);
method public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
method public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent);
+ method public void sendMultimediaMessage(@NonNull android.content.Context, @NonNull android.net.Uri, @Nullable String, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent, long);
method public void sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
method public void sendMultipartTextMessage(@NonNull String, @Nullable String, @NonNull java.util.List<java.lang.String>, @Nullable java.util.List<android.app.PendingIntent>, @Nullable java.util.List<android.app.PendingIntent>, long);
method public void sendMultipartTextMessage(@NonNull String, @Nullable String, @NonNull java.util.List<java.lang.String>, @Nullable java.util.List<android.app.PendingIntent>, @Nullable java.util.List<android.app.PendingIntent>, @NonNull String, @Nullable String);
@@ -46627,7 +46705,6 @@ package android.view {
method public long getAppVsyncOffsetNanos();
method public void getCurrentSizeRange(android.graphics.Point, android.graphics.Point);
method @Nullable public android.view.DisplayCutout getCutout();
- method @Nullable public android.hardware.display.DeviceProductInfo getDeviceProductInfo();
method public int getDisplayId();
method public int getFlags();
method public android.view.Display.HdrCapabilities getHdrCapabilities();
@@ -46898,6 +46975,7 @@ package android.view {
method public int getId();
method public android.view.KeyCharacterMap getKeyCharacterMap();
method public int getKeyboardType();
+ method @NonNull public android.hardware.lights.LightsManager getLightsManager();
method public android.view.InputDevice.MotionRange getMotionRange(int);
method public android.view.InputDevice.MotionRange getMotionRange(int, int);
method public java.util.List<android.view.InputDevice.MotionRange> getMotionRanges();
@@ -51631,6 +51709,7 @@ package android.view.inputmethod {
method public int describeContents();
method public void dump(android.util.Printer, String);
method public android.content.ComponentName getComponent();
+ method public int getConfigChanges();
method public String getId();
method public int getIsDefaultResourceId();
method public String getPackageName();
@@ -53312,6 +53391,7 @@ package android.widget {
method public int getCheckedItemPosition();
method public android.util.SparseBooleanArray getCheckedItemPositions();
method public int getChoiceMode();
+ method public int getEdgeEffectType();
method public int getListPaddingBottom();
method public int getListPaddingLeft();
method public int getListPaddingRight();
@@ -53353,6 +53433,7 @@ package android.widget {
method public void setChoiceMode(int);
method public void setDrawSelectorOnTop(boolean);
method public void setEdgeEffectColor(@ColorInt int);
+ method public void setEdgeEffectType(int);
method public void setFastScrollAlwaysVisible(boolean);
method public void setFastScrollEnabled(boolean);
method public void setFastScrollStyle(int);
@@ -53643,11 +53724,27 @@ package android.widget {
ctor @Deprecated public AnalogClock(android.content.Context, android.util.AttributeSet);
ctor @Deprecated public AnalogClock(android.content.Context, android.util.AttributeSet, int);
ctor @Deprecated public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
+ method @Deprecated @Nullable public android.graphics.BlendMode getDialTintBlendMode();
+ method @Deprecated @Nullable public android.content.res.ColorStateList getDialTintList();
+ method @Deprecated @Nullable public android.graphics.BlendMode getHourHandTintBlendMode();
+ method @Deprecated @Nullable public android.content.res.ColorStateList getHourHandTintList();
+ method @Deprecated @Nullable public android.graphics.BlendMode getMinuteHandTintBlendMode();
+ method @Deprecated @Nullable public android.content.res.ColorStateList getMinuteHandTintList();
+ method @Deprecated @Nullable public android.graphics.BlendMode getSecondHandTintBlendMode();
+ method @Deprecated @Nullable public android.content.res.ColorStateList getSecondHandTintList();
method @Deprecated @Nullable public String getTimeZone();
method @Deprecated public void setDial(@NonNull android.graphics.drawable.Icon);
+ method @Deprecated public void setDialTintBlendMode(@Nullable android.graphics.BlendMode);
+ method @Deprecated public void setDialTintList(@Nullable android.content.res.ColorStateList);
method @Deprecated public void setHourHand(@NonNull android.graphics.drawable.Icon);
+ method @Deprecated public void setHourHandTintBlendMode(@Nullable android.graphics.BlendMode);
+ method @Deprecated public void setHourHandTintList(@Nullable android.content.res.ColorStateList);
method @Deprecated public void setMinuteHand(@NonNull android.graphics.drawable.Icon);
+ method @Deprecated public void setMinuteHandTintBlendMode(@Nullable android.graphics.BlendMode);
+ method @Deprecated public void setMinuteHandTintList(@Nullable android.content.res.ColorStateList);
method @Deprecated public void setSecondHand(@Nullable android.graphics.drawable.Icon);
+ method @Deprecated public void setSecondHandTintBlendMode(@Nullable android.graphics.BlendMode);
+ method @Deprecated public void setSecondHandTintList(@Nullable android.content.res.ColorStateList);
method @Deprecated public void setTimeZone(@Nullable String);
}
@@ -54345,6 +54442,7 @@ package android.widget {
method public boolean executeKeyEvent(android.view.KeyEvent);
method public void fling(int);
method public boolean fullScroll(int);
+ method public int getEdgeEffectType();
method @ColorInt public int getLeftEdgeEffectColor();
method public int getMaxScrollAmount();
method @ColorInt public int getRightEdgeEffectColor();
@@ -54352,6 +54450,7 @@ package android.widget {
method public boolean isSmoothScrollingEnabled();
method public boolean pageScroll(int);
method public void setEdgeEffectColor(@ColorInt int);
+ method public void setEdgeEffectType(int);
method public void setFillViewport(boolean);
method public void setLeftEdgeEffectColor(@ColorInt int);
method public void setRightEdgeEffectColor(@ColorInt int);
@@ -55071,6 +55170,7 @@ package android.widget {
method public void setChronometerCountDown(@IdRes int, boolean);
method public void setColor(@IdRes int, @NonNull String, @ColorRes int);
method public void setColorInt(@IdRes int, @NonNull String, @ColorInt int, @ColorInt int);
+ method public void setColorStateList(@IdRes int, @NonNull String, @Nullable android.content.res.ColorStateList);
method public void setColorStateList(@IdRes int, @NonNull String, @Nullable android.content.res.ColorStateList, @Nullable android.content.res.ColorStateList);
method public void setColorStateList(@IdRes int, @NonNull String, @ColorRes int);
method public void setCompoundButtonChecked(@IdRes int, boolean);
@@ -55113,6 +55213,12 @@ package android.widget {
method public void setTextViewText(@IdRes int, CharSequence);
method public void setTextViewTextSize(@IdRes int, int, float);
method public void setUri(@IdRes int, String, android.net.Uri);
+ method public void setViewLayoutHeight(@IdRes int, float, int);
+ method public void setViewLayoutHeightDimen(@IdRes int, @DimenRes int);
+ method public void setViewLayoutMargin(@IdRes int, int, float, int);
+ method public void setViewLayoutMarginDimen(@IdRes int, int, @DimenRes int);
+ method public void setViewLayoutWidth(@IdRes int, float, int);
+ method public void setViewLayoutWidthDimen(@IdRes int, @DimenRes int);
method public void setViewOutlinePreferredRadius(@IdRes int, float, int);
method public void setViewOutlinePreferredRadiusDimen(@IdRes int, @DimenRes int);
method public void setViewPadding(@IdRes int, @Px int, @Px int, @Px int, @Px int);
@@ -55123,6 +55229,12 @@ package android.widget {
field @NonNull public static final android.os.Parcelable.Creator<android.widget.RemoteViews> CREATOR;
field public static final String EXTRA_CHECKED = "android.widget.extra.CHECKED";
field public static final String EXTRA_SHARED_ELEMENT_BOUNDS = "android.widget.extra.SHARED_ELEMENT_BOUNDS";
+ field public static final int MARGIN_BOTTOM = 3; // 0x3
+ field public static final int MARGIN_END = 5; // 0x5
+ field public static final int MARGIN_LEFT = 0; // 0x0
+ field public static final int MARGIN_RIGHT = 2; // 0x2
+ field public static final int MARGIN_START = 4; // 0x4
+ field public static final int MARGIN_TOP = 1; // 0x1
}
public static class RemoteViews.ActionException extends java.lang.RuntimeException {
@@ -55192,6 +55304,7 @@ package android.widget {
method public void fling(int);
method public boolean fullScroll(int);
method @ColorInt public int getBottomEdgeEffectColor();
+ method public int getEdgeEffectType();
method public int getMaxScrollAmount();
method @ColorInt public int getTopEdgeEffectColor();
method public boolean isFillViewport();
@@ -55200,6 +55313,7 @@ package android.widget {
method public void scrollToDescendant(@NonNull android.view.View);
method public void setBottomEdgeEffectColor(@ColorInt int);
method public void setEdgeEffectColor(@ColorInt int);
+ method public void setEdgeEffectType(int);
method public void setFillViewport(boolean);
method public void setSmoothScrollingEnabled(boolean);
method public void setTopEdgeEffectColor(@ColorInt int);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index de02d0bb7e98..dd9582fddd4a 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -135,7 +135,7 @@ package android.media.session {
}
public final class MediaSessionManager {
- method public void addOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, @Nullable android.content.ComponentName, @NonNull android.os.UserHandle, @Nullable android.os.Handler);
+ method public void addOnActiveSessionsChangedListener(@Nullable android.content.ComponentName, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener);
method public void dispatchMediaKeyEvent(@NonNull android.view.KeyEvent);
method public void dispatchMediaKeyEvent(@NonNull android.view.KeyEvent, boolean);
method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent);
@@ -189,6 +189,10 @@ package android.net {
field public static final int TRANSPORT_TEST = 7; // 0x7
}
+ public class NetworkWatchlistManager {
+ method @Nullable public byte[] getWatchlistConfigHash();
+ }
+
public final class Proxy {
method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo);
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index d79c11db9d09..05360141d9dd 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -884,7 +884,7 @@ package android.app.admin {
public class DevicePolicyManager {
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, "android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"}) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwnerNameOnAnyUser();
method @Nullable public CharSequence getDeviceOwnerOrganizationName();
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getDeviceOwnerUser();
@@ -1826,7 +1826,7 @@ package android.bluetooth {
method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public android.bluetooth.BufferConstraints getBufferConstraints();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getDynamicBufferSupport();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBufferMillis(int, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBufferLengthMillis(int, int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1; // 0x1
field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2; // 0x2
@@ -1942,6 +1942,10 @@ package android.bluetooth {
field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
}
+ public final class BluetoothMapClient implements android.bluetooth.BluetoothProfile {
+ method @RequiresPermission(android.Manifest.permission.SEND_SMS) public boolean sendMessage(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.Collection<android.net.Uri>, @NonNull String, @Nullable android.app.PendingIntent, @Nullable android.app.PendingIntent);
+ }
+
public final class BluetoothPan implements android.bluetooth.BluetoothProfile {
method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
@@ -1974,6 +1978,7 @@ package android.bluetooth {
field public static final int CONNECTION_POLICY_FORBIDDEN = 0; // 0x0
field public static final int CONNECTION_POLICY_UNKNOWN = -1; // 0xffffffff
field public static final int HEADSET_CLIENT = 16; // 0x10
+ field public static final int MAP_CLIENT = 18; // 0x12
field public static final int PAN = 5; // 0x5
field public static final int PBAP_CLIENT = 17; // 0x11
field @Deprecated public static final int PRIORITY_OFF = 0; // 0x0
@@ -2027,7 +2032,7 @@ package android.bluetooth {
public final class BufferConstraints implements android.os.Parcelable {
ctor public BufferConstraints(@NonNull java.util.List<android.bluetooth.BufferConstraint>);
method public int describeContents();
- method @Nullable public android.bluetooth.BufferConstraint getCodec(int);
+ method @Nullable public android.bluetooth.BufferConstraint forCodec(int);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final int BUFFER_CODEC_MAX_NUM = 32; // 0x20
field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BufferConstraints> CREATOR;
@@ -3398,42 +3403,12 @@ package android.hardware.hdmi {
package android.hardware.lights {
- public final class Light implements android.os.Parcelable {
- method public int describeContents();
- method public int getId();
- method public int getOrdinal();
- method public int getType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.Light> CREATOR;
- }
-
public final class LightState implements android.os.Parcelable {
- ctor public LightState(@ColorInt int);
- method public int describeContents();
- method @ColorInt public int getColor();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.LightState> CREATOR;
- }
-
- public final class LightsManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public java.util.List<android.hardware.lights.Light> getLights();
- method @NonNull @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public android.hardware.lights.LightsManager.LightsSession openSession();
- field public static final int LIGHT_TYPE_MICROPHONE = 8; // 0x8
- }
-
- public final class LightsManager.LightsSession implements java.lang.AutoCloseable {
- method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void close();
- method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void requestLights(@NonNull android.hardware.lights.LightsRequest);
- }
-
- public final class LightsRequest {
+ ctor @Deprecated public LightState(@ColorInt int);
}
- public static final class LightsRequest.Builder {
- ctor public LightsRequest.Builder();
- method @NonNull public android.hardware.lights.LightsRequest build();
- method @NonNull public android.hardware.lights.LightsRequest.Builder clearLight(@NonNull android.hardware.lights.Light);
- method @NonNull public android.hardware.lights.LightsRequest.Builder setLight(@NonNull android.hardware.lights.Light, @NonNull android.hardware.lights.LightState);
+ public abstract class LightsManager {
+ field @Deprecated public static final int LIGHT_TYPE_MICROPHONE = 8; // 0x8
}
}
@@ -4713,6 +4688,7 @@ package android.location {
}
public class LocationManager {
+ method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void addProviderRequestChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.provider.ProviderRequest.ChangedListener);
method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @Nullable public String getExtraLocationControllerPackage();
@@ -4727,7 +4703,7 @@ package android.location {
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String, @Nullable String);
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerProviderRequestListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.provider.ProviderRequest.Listener);
+ method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void removeProviderRequestChangedListener(@NonNull android.location.provider.ProviderRequest.ChangedListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
@@ -4736,7 +4712,6 @@ package android.location {
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser(@NonNull String, boolean, @NonNull android.os.UserHandle);
method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void unregisterProviderRequestListener(@NonNull android.location.provider.ProviderRequest.Listener);
}
public final class LocationRequest implements android.os.Parcelable {
@@ -4886,7 +4861,7 @@ package android.location.provider {
method @NonNull public android.location.provider.ProviderRequest.Builder setWorkSource(@NonNull android.os.WorkSource);
}
- public static interface ProviderRequest.Listener {
+ public static interface ProviderRequest.ChangedListener {
method public void onProviderRequestChanged(@NonNull String, @NonNull android.location.provider.ProviderRequest);
}
@@ -5097,7 +5072,7 @@ package android.media {
}
public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
- method @RequiresPermission(android.Manifest.permission.BIND_IMS_SERVICE) public void setOnRtpRxNoticeListener(@NonNull android.content.Context, @NonNull android.media.MediaPlayer.OnRtpRxNoticeListener, @Nullable android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.BIND_IMS_SERVICE) public void setOnRtpRxNoticeListener(@NonNull android.content.Context, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaPlayer.OnRtpRxNoticeListener);
}
public static interface MediaPlayer.OnRtpRxNoticeListener {
@@ -7941,6 +7916,28 @@ package android.net.util {
}
+package android.net.vcn {
+
+ public class VcnManager {
+ method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnNetworkPolicyListener);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.vcn.VcnNetworkPolicyResult applyVcnNetworkPolicy(@NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties);
+ method public void removeVcnNetworkPolicyListener(@NonNull android.net.vcn.VcnManager.VcnNetworkPolicyListener);
+ }
+
+ public static interface VcnManager.VcnNetworkPolicyListener {
+ method public void onPolicyChanged();
+ }
+
+ public final class VcnNetworkPolicyResult implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
+ method public boolean isTeardownRequested();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.vcn.VcnNetworkPolicyResult> CREATOR;
+ }
+
+}
+
package android.net.wifi {
public final class WifiMigration {
@@ -8288,7 +8285,7 @@ package android.os {
public final class BugreportManager {
method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.BugreportParams, @Nullable CharSequence, @Nullable CharSequence);
- method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
+ method @RequiresPermission(android.Manifest.permission.DUMP) @WorkerThread public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
}
public final class BugreportParams {
@@ -9221,6 +9218,7 @@ package android.provider {
field public static final String NAMESPACE_PERMISSIONS = "permissions";
field public static final String NAMESPACE_PRIVACY = "privacy";
field public static final String NAMESPACE_PROFCOLLECT_NATIVE_BOOT = "profcollect_native_boot";
+ field public static final String NAMESPACE_REBOOT_READINESS = "reboot_readiness";
field public static final String NAMESPACE_ROLLBACK = "rollback";
field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
field public static final String NAMESPACE_RUNTIME = "runtime";
@@ -10765,7 +10763,7 @@ package android.telecom {
method @Nullable public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
method @Nullable public final String getTelecomCallId();
method @Deprecated public void onAudioStateChanged(android.telecom.AudioState);
- method @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public void onCallFilteringCompleted(boolean, boolean, @Nullable android.telecom.CallScreeningService.CallResponse, boolean);
+ method @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public void onCallFilteringCompleted(@NonNull android.telecom.Connection.CallFilteringCompletionInfo);
method public final void resetConnectionTime();
method public void setCallDirection(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public final void setConnectTimeMillis(@IntRange(from=0) long);
@@ -10781,6 +10779,16 @@ package android.telecom {
field public static final int PROPERTY_REMOTELY_HOSTED = 2048; // 0x800
}
+ public static final class Connection.CallFilteringCompletionInfo implements android.os.Parcelable {
+ ctor public Connection.CallFilteringCompletionInfo(boolean, boolean, @Nullable android.telecom.CallScreeningService.CallResponse, @Nullable android.content.ComponentName);
+ method public int describeContents();
+ method @Nullable public android.telecom.CallScreeningService.CallResponse getCallResponse();
+ method @Nullable public android.content.ComponentName getCallScreeningComponent();
+ method public boolean isBlocked();
+ method public boolean isInContacts();
+ field @NonNull public static final android.os.Parcelable.Creator<android.telecom.Connection.CallFilteringCompletionInfo> CREATOR;
+ }
+
public final class ConnectionRequest implements android.os.Parcelable {
method @Nullable public String getTelecomCallId();
}
@@ -10942,7 +10950,7 @@ package android.telecom {
}
public final class RemoteConnection {
- method @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public void onCallFilteringCompleted(boolean, boolean, @Nullable android.telecom.CallScreeningService.CallResponse, boolean);
+ method @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public void onCallFilteringCompleted(@NonNull android.telecom.Connection.CallFilteringCompletionInfo);
method @Deprecated public void setAudioState(android.telecom.AudioState);
}
@@ -12253,6 +12261,7 @@ package android.telephony.data {
method public long getRetryDurationMillis();
method @Nullable public android.telephony.data.SliceInfo getSliceInfo();
method @Deprecated public int getSuggestedRetryTime();
+ method @NonNull public java.util.List<android.telephony.data.TrafficDescriptor> getTrafficDescriptors();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR;
field public static final int HANDOVER_FAILURE_MODE_DO_FALLBACK = 1; // 0x1
@@ -12288,6 +12297,7 @@ package android.telephony.data {
method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long);
method @NonNull public android.telephony.data.DataCallResponse.Builder setSliceInfo(@Nullable android.telephony.data.SliceInfo);
method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int);
+ method @NonNull public android.telephony.data.DataCallResponse.Builder setTrafficDescriptors(@NonNull java.util.List<android.telephony.data.TrafficDescriptor>);
}
public final class DataProfile implements android.os.Parcelable {
@@ -12358,7 +12368,7 @@ package android.telephony.data {
method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback);
method public void setInitialAttachApn(@NonNull android.telephony.data.DataProfile, boolean, @NonNull android.telephony.data.DataServiceCallback);
method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @NonNull android.telephony.data.DataServiceCallback);
- method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @Nullable android.telephony.data.SliceInfo, @NonNull android.telephony.data.DataServiceCallback);
+ method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @Nullable android.telephony.data.SliceInfo, @Nullable android.telephony.data.TrafficDescriptor, boolean, @NonNull android.telephony.data.DataServiceCallback);
}
public class DataServiceCallback {
@@ -12457,6 +12467,15 @@ package android.telephony.data {
method @NonNull public android.telephony.data.ThrottleStatus.Builder setTransportType(int);
}
+ public final class TrafficDescriptor implements android.os.Parcelable {
+ ctor public TrafficDescriptor(@Nullable String, @Nullable String);
+ method public int describeContents();
+ method @Nullable public String getDnn();
+ method @Nullable public String getOsAppId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.TrafficDescriptor> CREATOR;
+ }
+
}
package android.telephony.euicc {
@@ -14276,21 +14295,10 @@ package android.uwb {
public final class UwbManager {
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public long elapsedRealtimeResolutionNanos();
- method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getAngleOfArrivalSupport();
- method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getMaxRemoteDevicesPerInitiatorSession();
- method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getMaxRemoteDevicesPerResponderSession();
- method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getMaxSimultaneousSessions();
method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public android.os.PersistableBundle getSpecificationInfo();
- method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public java.util.List<java.lang.Integer> getSupportedChannelNumbers();
- method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public java.util.Set<java.lang.Integer> getSupportedPreambleCodeIndices();
- method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public boolean isRangingSupported();
method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public AutoCloseable openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback);
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void registerAdapterStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.uwb.UwbManager.AdapterStateCallback);
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void unregisterAdapterStateCallback(@NonNull android.uwb.UwbManager.AdapterStateCallback);
- field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D = 2; // 0x2
- field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 3; // 0x3
- field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 4; // 0x4
- field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE = 1; // 0x1
}
public static interface UwbManager.AdapterStateCallback {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index d7b43c0bc48e..835c49fccf7d 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -10,9 +10,11 @@ package android {
field public static final String BROADCAST_CLOSE_SYSTEM_DIALOGS = "android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS";
field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
+ field public static final String CLEAR_FREEZE_PERIOD = "android.permission.CLEAR_FREEZE_PERIOD";
field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
field public static final String CONTROL_DEVICE_LIGHTS = "android.permission.CONTROL_DEVICE_LIGHTS";
field public static final String CONTROL_DEVICE_STATE = "android.permission.CONTROL_DEVICE_STATE";
+ field public static final String FORCE_DEVICE_POLICY_MANAGER_LOGS = "android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS";
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final String KEEP_UNINSTALLED_PACKAGES = "android.permission.KEEP_UNINSTALLED_PACKAGES";
field @Deprecated public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
@@ -91,6 +93,8 @@ package android.app {
method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
method public void alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName);
method public long getTotalRam();
+ method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidProcessCapabilities(int);
+ method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidProcessState(int);
method public void holdLock(android.os.IBinder, int);
method public static boolean isHighEndGfx();
method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener);
@@ -100,13 +104,16 @@ package android.app {
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String);
field public static final long DROP_CLOSE_SYSTEM_DIALOGS = 174664120L; // 0xa6929b8L
field public static final long LOCK_DOWN_CLOSE_SYSTEM_DIALOGS = 174664365L; // 0xa692aadL
- field public static final int PROCESS_CAPABILITY_ALL = 7; // 0x7
+ field public static final int PROCESS_CAPABILITY_ALL = 15; // 0xf
field public static final int PROCESS_CAPABILITY_ALL_EXPLICIT = 1; // 0x1
field public static final int PROCESS_CAPABILITY_ALL_IMPLICIT = 6; // 0x6
field public static final int PROCESS_CAPABILITY_FOREGROUND_CAMERA = 2; // 0x2
field public static final int PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1; // 0x1
field public static final int PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 4; // 0x4
+ field public static final int PROCESS_CAPABILITY_NETWORK = 8; // 0x8
field public static final int PROCESS_CAPABILITY_NONE = 0; // 0x0
+ field public static final int PROCESS_STATE_FOREGROUND_SERVICE = 4; // 0x4
+ field public static final int PROCESS_STATE_TOP = 2; // 0x2
}
public static class ActivityManager.RunningAppProcessInfo implements android.os.Parcelable {
@@ -384,7 +391,11 @@ package android.app.admin {
public class DevicePolicyManager {
method public int checkProvisioningPreCondition(@Nullable String, @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.CLEAR_FREEZE_PERIOD) public void clearSystemUpdatePolicyFreezePeriodRecord();
method @Nullable public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException;
+ method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceNetworkLogs();
+ method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void forceRemoveActiveAdmin(@NonNull android.content.ComponentName, int);
+ method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceSecurityLogs();
method public void forceUpdateUserSetupComplete();
method public long getLastBugReportRequestTime();
method public long getLastNetworkLogRetrievalTime();
@@ -392,10 +403,13 @@ package android.app.admin {
method public java.util.List<java.lang.String> getOwnerInstalledCaCerts(@NonNull android.os.UserHandle);
method public boolean isCurrentInputMethodSetByOwner();
method public boolean isFactoryResetProtectionPolicySupported();
+ method @RequiresPermission(anyOf={"android.permission.MARK_DEVICE_ORGANIZATION_OWNED", "android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"}, conditional=true) public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName);
method @NonNull public static String operationSafetyReasonToString(int);
method @NonNull public static String operationToString(int);
method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException;
method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void resetDefaultCrossProfileIntentFilters(int);
+ method @RequiresPermission(allOf={"android.permission.MANAGE_DEVICE_ADMINS", android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void setActiveAdmin(@NonNull android.content.ComponentName, boolean, int);
+ method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public boolean setDeviceOwner(@NonNull android.content.ComponentName, @Nullable String, int);
method @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public void setNextOperationSafety(int, int);
field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
field public static final int CODE_ACCOUNTS_NOT_EMPTY = 6; // 0x6
@@ -580,6 +594,14 @@ package android.app.usage {
}
+package android.appwidget {
+
+ public class AppWidgetManager {
+ method public void setBindAppWidgetPermission(@NonNull String, int, boolean);
+ }
+
+}
+
package android.bluetooth {
public final class BluetoothClass implements android.os.Parcelable {
@@ -1001,14 +1023,6 @@ package android.hardware.input {
}
-package android.hardware.lights {
-
- public final class LightsManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public android.hardware.lights.LightState getLightState(@NonNull android.hardware.lights.Light);
- }
-
-}
-
package android.hardware.soundtrigger {
public class KeyphraseEnrollmentInfo {
@@ -2556,6 +2570,10 @@ package android.view.inputmethod {
method @NonNull public static android.view.inputmethod.InlineSuggestionsResponse newInlineSuggestionsResponse(@NonNull java.util.List<android.view.inputmethod.InlineSuggestion>);
}
+ public final class InputMethodInfo implements android.os.Parcelable {
+ ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int);
+ }
+
public final class InputMethodManager {
method public int getDisplayId();
method public boolean hasActiveInputConnection(@Nullable android.view.View);
diff --git a/core/java/android/app/ActivityManager.aidl b/core/java/android/app/ActivityManager.aidl
index 341393c0d969..eb7cac076822 100644
--- a/core/java/android/app/ActivityManager.aidl
+++ b/core/java/android/app/ActivityManager.aidl
@@ -17,6 +17,7 @@
package android.app;
parcelable ActivityManager.MemoryInfo;
+parcelable ActivityManager.PendingIntentInfo;
parcelable ActivityManager.ProcessErrorStateInfo;
parcelable ActivityManager.RecentTaskInfo;
parcelable ActivityManager.TaskDescription;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index e2426d116319..f905ec86aab7 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -511,6 +511,7 @@ public class ActivityManager {
/** @hide Process is hosting the current top activities. Note that this covers
* all activities that are visible to the user. */
@UnsupportedAppUsage
+ @TestApi
public static final int PROCESS_STATE_TOP = ProcessStateEnum.TOP;
/** @hide Process is bound to a TOP app. */
@@ -518,6 +519,7 @@ public class ActivityManager {
/** @hide Process is hosting a foreground service. */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @TestApi
public static final int PROCESS_STATE_FOREGROUND_SERVICE = ProcessStateEnum.FOREGROUND_SERVICE;
/** @hide Process is hosting a foreground service due to a system binding. */
@@ -616,11 +618,16 @@ public class ActivityManager {
@TestApi
public static final int PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 2;
+ /** @hide Process can access network despite any power saving resrictions */
+ @TestApi
+ public static final int PROCESS_CAPABILITY_NETWORK = 1 << 3;
+
/** @hide all capabilities, the ORing of all flags in {@link ProcessCapability}*/
@TestApi
public static final int PROCESS_CAPABILITY_ALL = PROCESS_CAPABILITY_FOREGROUND_LOCATION
| PROCESS_CAPABILITY_FOREGROUND_CAMERA
- | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+ | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
+ | PROCESS_CAPABILITY_NETWORK;
/**
* All explicit capabilities. These are capabilities that need to be specified from manifest
* file.
@@ -646,6 +653,15 @@ public class ActivityManager {
pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0 ? 'L' : '-');
pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0 ? 'C' : '-');
pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0 ? 'M' : '-');
+ pw.print((caps & PROCESS_CAPABILITY_NETWORK) != 0 ? 'N' : '-');
+ }
+
+ /** @hide */
+ public static void printCapabilitiesSummary(StringBuilder sb, @ProcessCapability int caps) {
+ sb.append((caps & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0 ? 'L' : '-');
+ sb.append((caps & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0 ? 'C' : '-');
+ sb.append((caps & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0 ? 'M' : '-');
+ sb.append((caps & PROCESS_CAPABILITY_NETWORK) != 0 ? 'N' : '-');
}
/**
@@ -656,13 +672,21 @@ public class ActivityManager {
printCapabilitiesSummary(pw, caps);
final int remain = caps & ~(PROCESS_CAPABILITY_FOREGROUND_LOCATION
| PROCESS_CAPABILITY_FOREGROUND_CAMERA
- | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE);
+ | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
+ | PROCESS_CAPABILITY_NETWORK);
if (remain != 0) {
pw.print('+');
pw.print(remain);
}
}
+ /** @hide */
+ public static String getCapabilitiesSummary(@ProcessCapability int caps) {
+ final StringBuilder sb = new StringBuilder();
+ printCapabilitiesSummary(sb, caps);
+ return sb.toString();
+ }
+
// NOTE: If PROCESS_STATEs are added, then new fields must be added
// to frameworks/base/core/proto/android/app/enums.proto and the following method must
// be updated to correctly map between them.
@@ -3411,6 +3435,36 @@ public class ActivityManager {
}
/**
+ * Returns the process state of this uid.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS)
+ public int getUidProcessState(int uid) {
+ try {
+ return getService().getUidProcessState(uid, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the process capability of this uid.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS)
+ public @ProcessCapability int getUidProcessCapabilities(int uid) {
+ try {
+ return getService().getUidProcessCapabilities(uid, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Return the importance of a given package name, based on the processes that are
* currently running. The return value is one of the importance constants defined
* in {@link RunningAppProcessInfo}, giving you the highest importance of all the
@@ -4485,6 +4539,80 @@ public class ActivityManager {
}
}
+ /** @hide */
+ public static String procStateToString(int procState) {
+ final String procStateStr;
+ switch (procState) {
+ case ActivityManager.PROCESS_STATE_PERSISTENT:
+ procStateStr = "PER ";
+ break;
+ case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
+ procStateStr = "PERU";
+ break;
+ case ActivityManager.PROCESS_STATE_TOP:
+ procStateStr = "TOP ";
+ break;
+ case ActivityManager.PROCESS_STATE_BOUND_TOP:
+ procStateStr = "BTOP";
+ break;
+ case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
+ procStateStr = "FGS ";
+ break;
+ case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
+ procStateStr = "BFGS";
+ break;
+ case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
+ procStateStr = "IMPF";
+ break;
+ case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
+ procStateStr = "IMPB";
+ break;
+ case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
+ procStateStr = "TRNB";
+ break;
+ case ActivityManager.PROCESS_STATE_BACKUP:
+ procStateStr = "BKUP";
+ break;
+ case ActivityManager.PROCESS_STATE_SERVICE:
+ procStateStr = "SVC ";
+ break;
+ case ActivityManager.PROCESS_STATE_RECEIVER:
+ procStateStr = "RCVR";
+ break;
+ case ActivityManager.PROCESS_STATE_TOP_SLEEPING:
+ procStateStr = "TPSL";
+ break;
+ case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
+ procStateStr = "HVY ";
+ break;
+ case ActivityManager.PROCESS_STATE_HOME:
+ procStateStr = "HOME";
+ break;
+ case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
+ procStateStr = "LAST";
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+ procStateStr = "CAC ";
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+ procStateStr = "CACC";
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_RECENT:
+ procStateStr = "CRE ";
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
+ procStateStr = "CEM ";
+ break;
+ case ActivityManager.PROCESS_STATE_NONEXISTENT:
+ procStateStr = "NONE";
+ break;
+ default:
+ procStateStr = "??";
+ break;
+ }
+ return procStateStr;
+ }
+
/**
* The AppTask allows you to manage your own application's tasks.
* See {@link android.app.ActivityManager#getAppTasks()}
@@ -4681,4 +4809,71 @@ public class ActivityManager {
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * A subset of immutable pending intent information suitable for caching on the client side.
+ *
+ * @hide
+ */
+ public static final class PendingIntentInfo implements Parcelable {
+
+ private final String mCreatorPackage;
+ private final int mCreatorUid;
+ private final boolean mImmutable;
+ private final int mIntentSenderType;
+
+ public PendingIntentInfo(String creatorPackage, int creatorUid, boolean immutable,
+ int intentSenderType) {
+ mCreatorPackage = creatorPackage;
+ mCreatorUid = creatorUid;
+ mImmutable = immutable;
+ mIntentSenderType = intentSenderType;
+ }
+
+ public String getCreatorPackage() {
+ return mCreatorPackage;
+ }
+
+ public int getCreatorUid() {
+ return mCreatorUid;
+ }
+
+ public boolean isImmutable() {
+ return mImmutable;
+ }
+
+ public int getIntentSenderType() {
+ return mIntentSenderType;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeString(mCreatorPackage);
+ parcel.writeInt(mCreatorUid);
+ parcel.writeBoolean(mImmutable);
+ parcel.writeInt(mIntentSenderType);
+ }
+
+ public static final @NonNull Creator<PendingIntentInfo> CREATOR =
+ new Creator<PendingIntentInfo>() {
+ @Override
+ public PendingIntentInfo createFromParcel(Parcel in) {
+ return new PendingIntentInfo(
+ /* creatorPackage= */ in.readString(),
+ /* creatorUid= */ in.readInt(),
+ /* immutable= */ in.readBoolean(),
+ /* intentSenderType= */ in.readInt());
+ }
+
+ @Override
+ public PendingIntentInfo[] newArray(int size) {
+ return new PendingIntentInfo[size];
+ }
+ };
+ }
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index b8735c731817..2f3b50b17d51 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2551,9 +2551,9 @@ public class AppOpsManager {
false, // READ_MEDIA_AUDIO
false, // WRITE_MEDIA_AUDIO
false, // READ_MEDIA_VIDEO
- false, // WRITE_MEDIA_VIDEO
+ true, // WRITE_MEDIA_VIDEO
false, // READ_MEDIA_IMAGES
- false, // WRITE_MEDIA_IMAGES
+ true, // WRITE_MEDIA_IMAGES
true, // LEGACY_STORAGE
false, // ACCESS_ACCESSIBILITY
false, // READ_DEVICE_IDENTIFIERS
diff --git a/core/java/android/app/BackgroundServiceStartNotAllowedException.java b/core/java/android/app/BackgroundServiceStartNotAllowedException.java
new file mode 100644
index 000000000000..f6361b52bf9d
--- /dev/null
+++ b/core/java/android/app/BackgroundServiceStartNotAllowedException.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Exception thrown when an app tries to start a background {@link Service} when it's not allowed to
+ * do so.
+ */
+public final class BackgroundServiceStartNotAllowedException
+ extends ServiceStartNotAllowedException implements Parcelable {
+ /**
+ * Constructor.
+ */
+ public BackgroundServiceStartNotAllowedException(@NonNull String message) {
+ super(message);
+ }
+
+ BackgroundServiceStartNotAllowedException(@NonNull Parcel source) {
+ super(source.readString());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(getMessage());
+ }
+
+ public static final @NonNull Creator<android.app.BackgroundServiceStartNotAllowedException>
+ CREATOR = new Creator<android.app.BackgroundServiceStartNotAllowedException>() {
+ @NonNull
+ public android.app.BackgroundServiceStartNotAllowedException createFromParcel(
+ Parcel source) {
+ return new android.app.BackgroundServiceStartNotAllowedException(source);
+ }
+
+ @NonNull
+ public android.app.BackgroundServiceStartNotAllowedException[] newArray(int size) {
+ return new android.app.BackgroundServiceStartNotAllowedException[size];
+ }
+ };
+}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 85fb543a3967..bc798136f2e3 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1796,7 +1796,7 @@ class ContextImpl extends Context {
"Unable to start service " + service
+ ": " + cn.getClassName());
} else if (cn.getPackageName().equals("?")) {
- throw new IllegalStateException(
+ throw ServiceStartNotAllowedException.newInstance(requireForeground,
"Not allowed to start service " + service + ": " + cn.getClassName());
}
}
diff --git a/core/java/android/app/ForegroundServiceStartNotAllowedException.java b/core/java/android/app/ForegroundServiceStartNotAllowedException.java
new file mode 100644
index 000000000000..41eeada2df6b
--- /dev/null
+++ b/core/java/android/app/ForegroundServiceStartNotAllowedException.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Exception thrown when an app tries to start a foreground {@link Service} when it's not allowed to
+ * do so.
+ */
+public final class ForegroundServiceStartNotAllowedException
+ extends ServiceStartNotAllowedException implements Parcelable {
+ /**
+ * Constructor.
+ */
+ public ForegroundServiceStartNotAllowedException(@NonNull String message) {
+ super(message);
+ }
+
+ ForegroundServiceStartNotAllowedException(@NonNull Parcel source) {
+ super(source.readString());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(getMessage());
+ }
+
+ public static final @NonNull Creator<android.app.ForegroundServiceStartNotAllowedException>
+ CREATOR = new Creator<android.app.ForegroundServiceStartNotAllowedException>() {
+ @NonNull
+ public android.app.ForegroundServiceStartNotAllowedException createFromParcel(
+ Parcel source) {
+ return new android.app.ForegroundServiceStartNotAllowedException(source);
+ }
+
+ @NonNull
+ public android.app.ForegroundServiceStartNotAllowedException[] newArray(int size) {
+ return new android.app.ForegroundServiceStartNotAllowedException[size];
+ }
+ };
+}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 4ad13e1932dd..2e684b1d3ef7 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -17,6 +17,7 @@
package android.app;
import android.app.ActivityManager;
+import android.app.ActivityManager.PendingIntentInfo;
import android.app.ActivityTaskManager;
import android.app.ApplicationErrorReport;
import android.app.ApplicationExitInfo;
@@ -248,7 +249,7 @@ interface IActivityManager {
in IBinder token, in String resultWho, int requestCode, in Intent[] intents,
in String[] resolvedTypes, int flags, in Bundle options, int userId);
void cancelIntentSender(in IIntentSender sender);
- String getPackageForIntentSender(in IIntentSender sender);
+ ActivityManager.PendingIntentInfo getInfoForIntentSender(in IIntentSender sender);
void registerIntentSenderCancelListener(in IIntentSender sender, in IResultReceiver receiver);
void unregisterIntentSenderCancelListener(in IIntentSender sender, in IResultReceiver receiver);
void enterSafeMode();
@@ -293,7 +294,6 @@ interface IActivityManager {
int operationType);
void backupAgentCreated(in String packageName, in IBinder agent, int userId);
void unbindBackupAgent(in ApplicationInfo appInfo);
- int getUidForIntentSender(in IIntentSender sender);
int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
boolean requireFull, in String name, in String callerPackage);
void addPackageDependency(in String packageName);
@@ -345,7 +345,6 @@ interface IActivityManager {
@UnsupportedAppUsage
void unregisterProcessObserver(in IProcessObserver observer);
boolean isIntentSenderTargetedToPackage(in IIntentSender sender);
- boolean isIntentSenderImmutable(in IIntentSender sender);
@UnsupportedAppUsage
void updatePersistentConfiguration(in Configuration values);
void updatePersistentConfigurationWithAttribution(in Configuration values,
@@ -375,8 +374,6 @@ interface IActivityManager {
void unstableProviderDied(in IBinder connection);
@UnsupportedAppUsage
boolean isIntentSenderAnActivity(in IIntentSender sender);
- boolean isIntentSenderAForegroundService(in IIntentSender sender);
- boolean isIntentSenderABroadcast(in IIntentSender sender);
/** @deprecated Use {@link startActivityAsUserWithFeature} instead */
@UnsupportedAppUsage(maxTargetSdk=29, publicAlternatives="Use {@code android.content.Context#createContextAsUser(android.os.UserHandle, int)} and {@link android.content.Context#startActivity(android.content.Intent)} instead")
int startActivityAsUser(in IApplicationThread caller, in String callingPackage,
@@ -711,5 +708,5 @@ interface IActivityManager {
/** Called by PendingIntent.queryIntentComponents() */
List<ResolveInfo> queryIntentComponentsForIntentSender(in IIntentSender sender, int matchFlags);
- boolean isIntentSenderAService(in IIntentSender sender);
+ int getUidProcessCapabilities(int uid, in String callingPackage);
}
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index b1c39d39d414..7bb5d9a8d387 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -60,9 +60,9 @@ oneway interface ITaskStackListener {
void onActivityForcedResizable(String packageName, int taskId, int reason);
/**
- * Called when we launched an activity that dismissed the docked stack.
+ * Called when we launched an activity that dismissed the docked task.
*/
- void onActivityDismissingDockedStack();
+ void onActivityDismissingDockedTask();
/**
* Called when an activity was requested to be launched on a secondary display but was not
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 899cdb5eb572..f7304fbee6d6 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1371,6 +1371,18 @@ public class Notification implements Parcelable
public static final String EXTRA_HANG_UP_INTENT = "android.hangUpIntent";
/**
+ * {@link #extras} key: the color used as a hint for the Answer action button of a
+ * {@link android.app.Notification.CallStyle} notification. This extra is a {@link ColorInt}.
+ */
+ public static final String EXTRA_ANSWER_COLOR = "android.answerColor";
+
+ /**
+ * {@link #extras} key: the color used as a hint for the Decline or Hang Up action button of a
+ * {@link android.app.Notification.CallStyle} notification. This extra is a {@link ColorInt}.
+ */
+ public static final String EXTRA_DECLINE_COLOR = "android.declineColor";
+
+ /**
* {@link #extras} key: whether the notification should be colorized as
* supplied to {@link Builder#setColorized(boolean)}.
*/
@@ -5444,6 +5456,11 @@ public class Notification implements Parcelable
return p.allowColorization && mN.isColorized();
}
+ private boolean isCallActionColorCustomizable(StandardTemplateParams p) {
+ return isColorized(p) && mContext.getResources().getBoolean(
+ R.bool.config_callNotificationActionColorsRequireColorized);
+ }
+
private void bindSmallIcon(RemoteViews contentView, StandardTemplateParams p) {
if (mN.mSmallIcon == null && mN.icon != 0) {
mN.mSmallIcon = Icon.createWithResource(mContext, mN.icon);
@@ -9066,6 +9083,8 @@ public class Notification implements Parcelable
private PendingIntent mAnswerIntent;
private PendingIntent mDeclineIntent;
private PendingIntent mHangUpIntent;
+ private Integer mAnswerButtonColor;
+ private Integer mDeclineButtonColor;
private Icon mVerificationIcon;
private CharSequence mVerificationText;
@@ -9176,6 +9195,28 @@ public class Notification implements Parcelable
}
/**
+ * Optional color to be used as a hint for the Answer action button's color.
+ * The system may change this color to ensure sufficient contrast with the background.
+ * The system may choose to disregard this hint if the notification is not colorized.
+ */
+ @NonNull
+ public CallStyle setAnswerButtonColorHint(@ColorInt int color) {
+ mAnswerButtonColor = color;
+ return this;
+ }
+
+ /**
+ * Optional color to be used as a hint for the Decline or Hang Up action button's color.
+ * The system may change this color to ensure sufficient contrast with the background.
+ * The system may choose to disregard this hint if the notification is not colorized.
+ */
+ @NonNull
+ public CallStyle setDeclineButtonColorHint(@ColorInt int color) {
+ mDeclineButtonColor = color;
+ return this;
+ }
+
+ /**
* @hide
*/
public boolean displayCustomViewInline() {
@@ -9234,40 +9275,47 @@ public class Notification implements Parcelable
}
@NonNull
- private Action makeNegativeAction() {
+ private Action makeNegativeAction(@NonNull StandardTemplateParams p) {
if (mDeclineIntent == null) {
- return makeAction(R.drawable.ic_call_decline,
+ return makeAction(p, R.drawable.ic_call_decline,
R.string.call_notification_hang_up_action,
- R.color.call_notification_decline_color, mHangUpIntent);
+ mDeclineButtonColor, R.color.call_notification_decline_color,
+ mHangUpIntent);
} else {
- return makeAction(R.drawable.ic_call_decline,
+ return makeAction(p, R.drawable.ic_call_decline,
R.string.call_notification_decline_action,
- R.color.call_notification_decline_color, mDeclineIntent);
+ mDeclineButtonColor, R.color.call_notification_decline_color,
+ mDeclineIntent);
}
}
@Nullable
- private Action makeAnswerAction() {
- return mAnswerIntent == null ? null : makeAction(R.drawable.ic_call_answer,
+ private Action makeAnswerAction(@NonNull StandardTemplateParams p) {
+ return mAnswerIntent == null ? null : makeAction(p, R.drawable.ic_call_answer,
R.string.call_notification_answer_action,
- R.color.call_notification_answer_color, mAnswerIntent);
+ mAnswerButtonColor, R.color.call_notification_answer_color,
+ mAnswerIntent);
}
@NonNull
- private Action makeAction(@DrawableRes int icon, @StringRes int title,
- @ColorRes int colorRes, PendingIntent intent) {
+ private Action makeAction(@NonNull StandardTemplateParams p,
+ @DrawableRes int icon, @StringRes int title,
+ @ColorInt Integer colorInt, @ColorRes int defaultColorRes, PendingIntent intent) {
+ if (colorInt == null || !mBuilder.isCallActionColorCustomizable(p)) {
+ colorInt = mBuilder.mContext.getColor(defaultColorRes);
+ }
Action action = new Action.Builder(Icon.createWithResource("", icon),
new SpannableStringBuilder().append(mBuilder.mContext.getString(title),
- new ForegroundColorSpan(mBuilder.mContext.getColor(colorRes)),
+ new ForegroundColorSpan(colorInt),
SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE),
intent).build();
action.getExtras().putBoolean(KEY_ACTION_PRIORITY, true);
return action;
}
- private ArrayList<Action> makeActionsList() {
- final Action negativeAction = makeNegativeAction();
- final Action answerAction = makeAnswerAction();
+ private ArrayList<Action> makeActionsList(@NonNull StandardTemplateParams p) {
+ final Action negativeAction = makeNegativeAction(p);
+ final Action answerAction = makeAnswerAction(p);
ArrayList<Action> actions = new ArrayList<>(MAX_ACTION_BUTTONS);
final Action lastAction;
@@ -9356,7 +9404,7 @@ public class Notification implements Parcelable
// Create the buttons for the generated actions list.
int i = 0;
- for (Action action : makeActionsList()) {
+ for (Action action : makeActionsList(p)) {
final RemoteViews button = mBuilder.generateActionButton(action, emphasizedMode, p);
if (i > 0) {
// Clear start margin from non-first buttons to reduce the gap between buttons.
@@ -9421,6 +9469,12 @@ public class Notification implements Parcelable
if (mHangUpIntent != null) {
extras.putParcelable(EXTRA_HANG_UP_INTENT, mHangUpIntent);
}
+ if (mAnswerButtonColor != null) {
+ extras.putInt(EXTRA_ANSWER_COLOR, mAnswerButtonColor);
+ }
+ if (mDeclineButtonColor != null) {
+ extras.putInt(EXTRA_DECLINE_COLOR, mDeclineButtonColor);
+ }
fixTitleAndTextExtras(extras);
}
@@ -9447,6 +9501,10 @@ public class Notification implements Parcelable
mAnswerIntent = extras.getParcelable(EXTRA_ANSWER_INTENT);
mDeclineIntent = extras.getParcelable(EXTRA_DECLINE_INTENT);
mHangUpIntent = extras.getParcelable(EXTRA_HANG_UP_INTENT);
+ mAnswerButtonColor = extras.containsKey(EXTRA_ANSWER_COLOR)
+ ? extras.getInt(EXTRA_ANSWER_COLOR) : null;
+ mDeclineButtonColor = extras.containsKey(EXTRA_DECLINE_COLOR)
+ ? extras.getInt(EXTRA_DECLINE_COLOR) : null;
}
/**
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 671315f37b20..2f06bdce9087 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -16,6 +16,11 @@
package android.app;
+import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
+import static android.app.ActivityManager.INTENT_SENDER_BROADCAST;
+import static android.app.ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.INTENT_SENDER_SERVICE;
+
import android.Manifest.permission;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -25,6 +30,7 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemApi.Client;
import android.annotation.TestApi;
+import android.app.ActivityManager.PendingIntentInfo;
import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
@@ -122,6 +128,9 @@ public final class PendingIntent implements Parcelable {
private IBinder mWhitelistToken;
private ArraySet<CancelListener> mCancelListeners;
+ // cached pending intent information
+ private @Nullable PendingIntentInfo mCachedInfo;
+
/**
* It is now required to specify either {@link #FLAG_IMMUTABLE}
* or {@link #FLAG_MUTABLE} when creating a PendingIntent.
@@ -463,7 +472,7 @@ public final class PendingIntent implements Parcelable {
intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
- ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+ INTENT_SENDER_ACTIVITY, packageName,
context.getAttributionTag(), null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
flags, options, user.getIdentifier());
@@ -596,7 +605,7 @@ public final class PendingIntent implements Parcelable {
try {
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
- ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+ INTENT_SENDER_ACTIVITY, packageName,
context.getAttributionTag(), null, null, requestCode, intents, resolvedTypes,
flags, options, user.getIdentifier());
return target != null ? new PendingIntent(target) : null;
@@ -650,7 +659,7 @@ public final class PendingIntent implements Parcelable {
intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
- ActivityManager.INTENT_SENDER_BROADCAST, packageName,
+ INTENT_SENDER_BROADCAST, packageName,
context.getAttributionTag(), null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
flags, null, userHandle.getIdentifier());
@@ -687,7 +696,7 @@ public final class PendingIntent implements Parcelable {
public static PendingIntent getService(Context context, int requestCode,
@NonNull Intent intent, @Flags int flags) {
return buildServicePendingIntent(context, requestCode, intent, flags,
- ActivityManager.INTENT_SENDER_SERVICE);
+ INTENT_SENDER_SERVICE);
}
/**
@@ -717,7 +726,7 @@ public final class PendingIntent implements Parcelable {
public static PendingIntent getForegroundService(Context context, int requestCode,
@NonNull Intent intent, @Flags int flags) {
return buildServicePendingIntent(context, requestCode, intent, flags,
- ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE);
+ INTENT_SENDER_FOREGROUND_SERVICE);
}
private static PendingIntent buildServicePendingIntent(Context context, int requestCode,
@@ -1001,12 +1010,7 @@ public final class PendingIntent implements Parcelable {
*/
@Deprecated
public String getTargetPackage() {
- try {
- return ActivityManager.getService()
- .getPackageForIntentSender(mTarget);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getCreatorPackage();
}
/**
@@ -1029,12 +1033,7 @@ public final class PendingIntent implements Parcelable {
*/
@Nullable
public String getCreatorPackage() {
- try {
- return ActivityManager.getService()
- .getPackageForIntentSender(mTarget);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getCachedInfo().getCreatorPackage();
}
/**
@@ -1056,12 +1055,7 @@ public final class PendingIntent implements Parcelable {
* none associated with it.
*/
public int getCreatorUid() {
- try {
- return ActivityManager.getService()
- .getUidForIntentSender(mTarget);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getCachedInfo().getCreatorUid();
}
/**
@@ -1154,13 +1148,8 @@ public final class PendingIntent implements Parcelable {
*/
@Nullable
public UserHandle getCreatorUserHandle() {
- try {
- int uid = ActivityManager.getService()
- .getUidForIntentSender(mTarget);
- return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ int uid = getCachedInfo().getCreatorUid();
+ return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null;
}
/**
@@ -1180,12 +1169,7 @@ public final class PendingIntent implements Parcelable {
* Check if this PendingIntent is marked with {@link #FLAG_IMMUTABLE}.
*/
public boolean isImmutable() {
- try {
- return ActivityManager.getService()
- .isIntentSenderImmutable(mTarget);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getCachedInfo().isImmutable();
}
/**
@@ -1193,48 +1177,28 @@ public final class PendingIntent implements Parcelable {
* {@link #getActivity} or {@link #getActivities}.
*/
public boolean isActivity() {
- try {
- return ActivityManager.getService()
- .isIntentSenderAnActivity(mTarget);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getCachedInfo().getIntentSenderType() == INTENT_SENDER_ACTIVITY;
}
/**
* @return TRUE if this {@link PendingIntent} was created with {@link #getForegroundService}.
*/
public boolean isForegroundService() {
- try {
- return ActivityManager.getService()
- .isIntentSenderAForegroundService(mTarget);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getCachedInfo().getIntentSenderType() == INTENT_SENDER_FOREGROUND_SERVICE;
}
/**
* @return TRUE if this {@link PendingIntent} was created with {@link #getService}.
*/
public boolean isService() {
- try {
- return ActivityManager.getService()
- .isIntentSenderAService(mTarget);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getCachedInfo().getIntentSenderType() == INTENT_SENDER_SERVICE;
}
/**
* @return TRUE if this {@link PendingIntent} was created with {@link #getBroadcast}.
*/
public boolean isBroadcast() {
- try {
- return ActivityManager.getService()
- .isIntentSenderABroadcast(mTarget);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getCachedInfo().getIntentSenderType() == INTENT_SENDER_BROADCAST;
}
/**
@@ -1433,4 +1397,16 @@ public final class PendingIntent implements Parcelable {
*/
void onCancelled(PendingIntent intent);
}
+
+ private PendingIntentInfo getCachedInfo() {
+ if (mCachedInfo == null) {
+ try {
+ mCachedInfo = ActivityManager.getService().getInfoForIntentSender(mTarget);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ return mCachedInfo;
+ }
}
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 3798de921dc7..2ceea7f1a6a8 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -697,7 +697,8 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
* service element of manifest file. The value of attribute
* {@link android.R.attr#foregroundServiceType} can be multiple flags ORed together.</p>
*
- * @throws IllegalStateException If the app targeting API is
+ * @throws ForegroundServiceStartNotAllowedException
+ * If the app targeting API is
* {@link android.os.Build.VERSION_CODES#S} or later, and the service is restricted from
* becoming foreground service due to background restriction.
*
@@ -738,8 +739,14 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
* @param notification The Notification to be displayed.
* @param foregroundServiceType must be a subset flags of manifest attribute
* {@link android.R.attr#foregroundServiceType} flags.
+ *
* @throws IllegalArgumentException if param foregroundServiceType is not subset of manifest
* attribute {@link android.R.attr#foregroundServiceType}.
+ * @throws ForegroundServiceStartNotAllowedException
+ * If the app targeting API is
+ * {@link android.os.Build.VERSION_CODES#S} or later, and the service is restricted from
+ * becoming foreground service due to background restriction.
+ *
* @see android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MANIFEST
*/
public final void startForeground(int id, @NonNull Notification notification,
diff --git a/core/java/android/app/ServiceStartNotAllowedException.java b/core/java/android/app/ServiceStartNotAllowedException.java
new file mode 100644
index 000000000000..33285b2190eb
--- /dev/null
+++ b/core/java/android/app/ServiceStartNotAllowedException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.annotation.NonNull;
+
+/**
+ * Exception thrown when an app tries to start a {@link Service} when it's not allowed to do so.
+ */
+public abstract class ServiceStartNotAllowedException extends IllegalStateException {
+ ServiceStartNotAllowedException(@NonNull String message) {
+ super(message);
+ }
+
+ /**
+ * Return either {@link ForegroundServiceStartNotAllowedException} or
+ * {@link BackgroundServiceStartNotAllowedException}
+ * @hide
+ */
+ @NonNull
+ public static ServiceStartNotAllowedException newInstance(boolean foreground,
+ @NonNull String message) {
+ if (foreground) {
+ return new ForegroundServiceStartNotAllowedException(message);
+ } else {
+ return new BackgroundServiceStartNotAllowedException(message);
+ }
+ }
+}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index ffaaa578cdd2..e16e40b6d572 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -47,6 +47,7 @@ import android.app.usage.IUsageStatsManager;
import android.app.usage.NetworkStatsManager;
import android.app.usage.StorageStatsManager;
import android.app.usage.UsageStatsManager;
+import android.apphibernation.AppHibernationManager;
import android.appwidget.AppWidgetManager;
import android.bluetooth.BluetoothManager;
import android.companion.CompanionDeviceManager;
@@ -99,6 +100,7 @@ import android.hardware.input.InputManager;
import android.hardware.iris.IIrisService;
import android.hardware.iris.IrisManager;
import android.hardware.lights.LightsManager;
+import android.hardware.lights.SystemLightsManager;
import android.hardware.location.ContextHubManager;
import android.hardware.radio.RadioManager;
import android.hardware.usb.IUsbManager;
@@ -1344,7 +1346,7 @@ public final class SystemServiceRegistry {
@Override
public LightsManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
- return new LightsManager(ctx);
+ return new SystemLightsManager(ctx);
}});
registerService(Context.INCREMENTAL_SERVICE, IncrementalManager.class,
new CachedServiceFetcher<IncrementalManager>() {
@@ -1377,6 +1379,13 @@ public final class SystemServiceRegistry {
IBinder b = ServiceManager.getServiceOrThrow(Context.APP_INTEGRITY_SERVICE);
return new AppIntegrityManager(IAppIntegrityManager.Stub.asInterface(b));
}});
+ registerService(Context.APP_HIBERNATION_SERVICE, AppHibernationManager.class,
+ new CachedServiceFetcher<AppHibernationManager>() {
+ @Override
+ public AppHibernationManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.APP_HIBERNATION_SERVICE);
+ return b == null ? null : new AppHibernationManager(ctx);
+ }});
registerService(Context.DREAM_SERVICE, DreamManager.class,
new CachedServiceFetcher<DreamManager>() {
@Override
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 1e382307a1a3..f523a7d29713 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -43,7 +43,7 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub {
@Override
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public void onActivityPinned(String packageName, int userId, int taskId, int stackId)
+ public void onActivityPinned(String packageName, int userId, int taskId, int rootTaskId)
throws RemoteException {
}
@@ -66,7 +66,7 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub {
@Override
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public void onActivityDismissingDockedStack() throws RemoteException {
+ public void onActivityDismissingDockedTask() throws RemoteException {
}
@Override
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index 2d203f57a66f..3abba43ae0a8 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -30,14 +30,17 @@ import android.util.Log;
import android.util.Size;
import com.android.internal.graphics.ColorUtils;
+import com.android.internal.graphics.palette.CelebiQuantizer;
import com.android.internal.graphics.palette.Palette;
-import com.android.internal.graphics.palette.VariationalKMeansQuantizer;
import com.android.internal.util.ContrastColorUtil;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
/**
* Provides information about the colors of a wallpaper.
@@ -94,16 +97,21 @@ public final class WallpaperColors implements Parcelable {
private static final float DARK_PIXEL_CONTRAST = 6f;
private static final float MAX_DARK_AREA = 0.025f;
- private final ArrayList<Color> mMainColors;
+ private final List<Color> mMainColors;
+ private final Map<Integer, Integer> mAllColors;
private int mColorHints;
public WallpaperColors(Parcel parcel) {
mMainColors = new ArrayList<>();
+ mAllColors = new HashMap<>();
final int count = parcel.readInt();
for (int i = 0; i < count; i++) {
final int colorInt = parcel.readInt();
Color color = Color.valueOf(colorInt);
mMainColors.add(color);
+
+ final int population = parcel.readInt();
+ mAllColors.put(colorInt, population);
}
mColorHints = parcel.readInt();
}
@@ -166,39 +174,22 @@ public final class WallpaperColors implements Parcelable {
}
final Palette palette = Palette
- .from(bitmap)
- .setQuantizer(new VariationalKMeansQuantizer())
- .maximumColorCount(5)
- .clearFilters()
+ .from(bitmap, new CelebiQuantizer())
+ .maximumColorCount(256)
.resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA)
.generate();
-
// Remove insignificant colors and sort swatches by population
final ArrayList<Palette.Swatch> swatches = new ArrayList<>(palette.getSwatches());
- final float minColorArea = bitmap.getWidth() * bitmap.getHeight() * MIN_COLOR_OCCURRENCE;
- swatches.removeIf(s -> s.getPopulation() < minColorArea);
swatches.sort((a, b) -> b.getPopulation() - a.getPopulation());
final int swatchesSize = swatches.size();
- Color primary = null, secondary = null, tertiary = null;
- swatchLoop:
+ final Map<Integer, Integer> populationByColor = new HashMap<>();
for (int i = 0; i < swatchesSize; i++) {
- Color color = Color.valueOf(swatches.get(i).getRgb());
- switch (i) {
- case 0:
- primary = color;
- break;
- case 1:
- secondary = color;
- break;
- case 2:
- tertiary = color;
- break;
- default:
- // out of bounds
- break swatchLoop;
- }
+ Palette.Swatch swatch = swatches.get(i);
+ int colorInt = swatch.getInt();
+ populationByColor.put(colorInt, swatch.getPopulation());
+
}
int hints = calculateDarkHints(bitmap);
@@ -207,7 +198,7 @@ public final class WallpaperColors implements Parcelable {
bitmap.recycle();
}
- return new WallpaperColors(primary, secondary, tertiary, HINT_FROM_BITMAP | hints);
+ return new WallpaperColors(populationByColor, HINT_FROM_BITMAP | hints);
}
/**
@@ -253,9 +244,13 @@ public final class WallpaperColors implements Parcelable {
}
mMainColors = new ArrayList<>(3);
+ mAllColors = new HashMap<>();
+
mMainColors.add(primaryColor);
+ mAllColors.put(primaryColor.toArgb(), 0);
if (secondaryColor != null) {
mMainColors.add(secondaryColor);
+ mAllColors.put(secondaryColor.toArgb(), 0);
}
if (tertiaryColor != null) {
if (secondaryColor == null) {
@@ -263,8 +258,32 @@ public final class WallpaperColors implements Parcelable {
+ "secondaryColor is null");
}
mMainColors.add(tertiaryColor);
+ mAllColors.put(tertiaryColor.toArgb(), 0);
}
+ mColorHints = colorHints;
+ }
+ /**
+ * Constructs a new object from a set of colors, where hints can be specified.
+ *
+ * @param populationByColor Map with keys of colors, and value representing the number of
+ * occurrences of color in the wallpaper.
+ * @param colorHints A combination of WallpaperColor hints.
+ * @hide
+ * @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
+ * @see WallpaperColors#fromBitmap(Bitmap)
+ * @see WallpaperColors#fromDrawable(Drawable)
+ */
+ public WallpaperColors(@NonNull Map<Integer, Integer> populationByColor, int colorHints) {
+ mAllColors = populationByColor;
+
+ ArrayList<Map.Entry<Integer, Integer>> mapEntries = new ArrayList(
+ populationByColor.entrySet());
+ mapEntries.sort((a, b) ->
+ a.getValue().compareTo(b.getValue())
+ );
+ mMainColors = mapEntries.stream().map(entry -> Color.valueOf(entry.getKey())).collect(
+ Collectors.toList());
mColorHints = colorHints;
}
@@ -293,6 +312,9 @@ public final class WallpaperColors implements Parcelable {
for (int i = 0; i < count; i++) {
Color color = mainColors.get(i);
dest.writeInt(color.toArgb());
+ Integer population = mAllColors.get(color.toArgb());
+ int populationInt = (population != null) ? population : 0;
+ dest.writeInt(populationInt);
}
dest.writeInt(mColorHints);
}
@@ -336,6 +358,17 @@ public final class WallpaperColors implements Parcelable {
return Collections.unmodifiableList(mMainColors);
}
+ /**
+ * Map of all colors. Key is rgb integer, value is importance of color.
+ *
+ * @return List of colors.
+ * @hide
+ */
+ public @NonNull Map<Integer, Integer> getAllColors() {
+ return Collections.unmodifiableMap(mAllColors);
+ }
+
+
@Override
public boolean equals(@Nullable Object o) {
if (o == null || getClass() != o.getClass()) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 59e5144113c9..bb1ff6051d56 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2746,6 +2746,32 @@ public class DevicePolicyManager {
@Retention(RetentionPolicy.SOURCE)
public @interface PersonalAppsSuspensionReason {}
+ /**
+ * The default device owner type for a managed device.
+ *
+ * @hide
+ */
+ public static final int DEVICE_OWNER_TYPE_DEFAULT = 0;
+
+ /**
+ * The device owner type for a financed device.
+ *
+ * @hide
+ */
+ public static final int DEVICE_OWNER_TYPE_FINANCED = 1;
+
+ /**
+ * Different device owner types for a managed device.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "DEVICE_OWNER_TYPE_" }, value = {
+ DEVICE_OWNER_TYPE_DEFAULT,
+ DEVICE_OWNER_TYPE_FINANCED
+ })
+ public @interface DeviceOwnerType {}
+
/** @hide */
@TestApi
public static final int OPERATION_LOCK_NOW = 1;
@@ -7276,7 +7302,12 @@ public class DevicePolicyManager {
/**
* @hide
*/
+ @TestApi
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.MANAGE_DEVICE_ADMINS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL
+ })
public void setActiveAdmin(@NonNull ComponentName policyReceiver, boolean refreshing,
int userHandle) {
if (mService != null) {
@@ -7453,8 +7484,10 @@ public class DevicePolicyManager {
* @throws IllegalArgumentException if the package name is null or invalid
* @throws IllegalStateException If the preconditions mentioned are not met.
*/
- public boolean setDeviceOwner(ComponentName who, String ownerName, int userId)
- throws IllegalArgumentException, IllegalStateException {
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ public boolean setDeviceOwner(
+ @NonNull ComponentName who, @Nullable String ownerName, @UserIdInt int userId) {
if (mService != null) {
try {
return mService.setDeviceOwner(who, ownerName, userId);
@@ -7521,7 +7554,10 @@ public class DevicePolicyManager {
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
+ })
public ComponentName getDeviceOwnerComponentOnAnyUser() {
return getDeviceOwnerComponentInner(/* callingUserOnly =*/ false);
}
@@ -10477,9 +10513,10 @@ public class DevicePolicyManager {
/**
* Reset record of previous system update freeze period the device went through.
- * Only callable by ADB.
* @hide
*/
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.CLEAR_FREEZE_PERIOD)
public void clearSystemUpdatePolicyFreezePeriodRecord() {
throwIfParentInstance("clearSystemUpdatePolicyFreezePeriodRecord");
if (mService == null) {
@@ -11207,9 +11244,11 @@ public class DevicePolicyManager {
/**
* Makes all accumulated network logs available to DPC in a new batch.
- * Only callable by ADB. If throttled, returns time to wait in milliseconds, otherwise 0.
+ * If throttled, returns time to wait in milliseconds, otherwise 0.
* @hide
*/
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS)
public long forceNetworkLogs() {
if (mService == null) {
return -1;
@@ -11223,9 +11262,11 @@ public class DevicePolicyManager {
/**
* Forces a batch of security logs to be fetched from logd and makes it available for DPC.
- * Only callable by ADB. If throttled, returns time to wait in milliseconds, otherwise 0.
+ * If throttled, returns time to wait in milliseconds, otherwise 0.
* @hide
*/
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS)
public long forceSecurityLogs() {
if (mService == null) {
return 0;
@@ -11657,7 +11698,10 @@ public class DevicePolicyManager {
* @throws SecurityException if the caller is not shell / root or the admin package
* isn't a test application see {@link ApplicationInfo#FLAG_TEST_APP}.
*/
- public void forceRemoveActiveAdmin(ComponentName adminReceiver, int userHandle) {
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ public void forceRemoveActiveAdmin(
+ @NonNull ComponentName adminReceiver, @UserIdInt int userHandle) {
try {
mService.forceRemoveActiveAdmin(adminReceiver, userHandle);
} catch (RemoteException re) {
@@ -12727,8 +12771,11 @@ public class DevicePolicyManager {
*
* @hide
*/
- @RequiresPermission(value = android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED,
- conditional = true)
+ @TestApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED,
+ android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS
+ }, conditional = true)
public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull ComponentName who) {
if (mService == null) {
return;
@@ -13460,6 +13507,57 @@ public class DevicePolicyManager {
}
/**
+ * Sets the device owner type for a managed device (e.g. financed device).
+ *
+ * @param admin The {@link DeviceAdminReceiver} that is the device owner.
+ * @param deviceOwnerType The device owner type is set to. Use
+ * {@link #DEVICE_OWNER_TYPE_DEFAULT} for the default device owner type. Use
+ * {@link #DEVICE_OWNER_TYPE_FINANCED} for the financed device owner type.
+ *
+ * @throws IllegalStateException When admin is not the device owner, or there is no device
+ * owner, or attempting to set the device owner type again for the same admin.
+ * @throws SecurityException If the caller does not have the permission
+ * {@link permission#MANAGE_PROFILE_AND_DEVICE_OWNERS}.
+ *
+ * @hide
+ */
+ public void setDeviceOwnerType(@NonNull ComponentName admin,
+ @DeviceOwnerType int deviceOwnerType) {
+ throwIfParentInstance("setDeviceOwnerType");
+ if (mService != null) {
+ try {
+ mService.setDeviceOwnerType(admin, deviceOwnerType);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Returns the device owner type for the admin used in
+ * {@link #setDeviceOwnerType(ComponentName, int)}. {@link #DEVICE_OWNER_TYPE_DEFAULT}
+ * would be returned when the device owner type is not set for the device owner admin.
+ *
+ * @param admin The {@link DeviceAdminReceiver} that is the device owner.
+ *
+ * @throws IllegalStateException When admin is not the device owner or there is no device owner.
+ *
+ * @hide
+ */
+ @DeviceOwnerType
+ public int getDeviceOwnerType(@NonNull ComponentName admin) {
+ throwIfParentInstance("getDeviceOwnerType");
+ if (mService != null) {
+ try {
+ return mService.getDeviceOwnerType(admin);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ return DEVICE_OWNER_TYPE_DEFAULT;
+ }
+
+ /**
* Called by device owner or profile owner of an organization-owned managed profile to
* enable or disable USB data signaling for the device. When disabled, USB data connections
* (except from charging functions) are prohibited.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 8a87b16b760b..ac1592d2d2a1 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -503,6 +503,9 @@ interface IDevicePolicyManager {
UserHandle createAndProvisionManagedProfile(in ManagedProfileProvisioningParams provisioningParams, in String callerPackage);
void provisionFullyManagedDevice(in FullyManagedDeviceProvisioningParams provisioningParams, in String callerPackage);
+ void setDeviceOwnerType(in ComponentName admin, in int deviceOwnerType);
+ int getDeviceOwnerType(in ComponentName admin);
+
void resetDefaultCrossProfileIntentFilters(int userId);
boolean canAdminGrantSensorsPermissionsForUser(int userId);
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 673de8fa7c8c..dae565e12fd7 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -361,36 +361,7 @@ public class BackupManager {
try {
// All packages, current transport
IRestoreSession binder =
- sService.beginRestoreSessionForUser(mContext.getUserId(), null, null,
- OperationType.BACKUP);
- if (binder != null) {
- session = new RestoreSession(mContext, binder);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "beginRestoreSession() couldn't connect");
- }
- }
- return session;
- }
-
- /**
- * Begin the process of restoring data from backup. See the
- * {@link android.app.backup.RestoreSession} class for documentation on that process.
- *
- * @param operationType Type of the operation, see {@link OperationType}
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.BACKUP)
- public RestoreSession beginRestoreSession(@OperationType int operationType) {
- RestoreSession session = null;
- checkServiceBinder();
- if (sService != null) {
- try {
- // All packages, current transport
- IRestoreSession binder =
- sService.beginRestoreSessionForUser(mContext.getUserId(), null, null,
- operationType);
+ sService.beginRestoreSessionForUser(mContext.getUserId(), null, null);
if (binder != null) {
session = new RestoreSession(mContext, binder);
}
@@ -801,7 +772,7 @@ public class BackupManager {
@SystemApi
@RequiresPermission(android.Manifest.permission.BACKUP)
public int requestBackup(String[] packages, BackupObserver observer) {
- return requestBackup(packages, observer, null, 0, OperationType.BACKUP);
+ return requestBackup(packages, observer, null, 0);
}
/**
@@ -826,31 +797,6 @@ public class BackupManager {
@RequiresPermission(android.Manifest.permission.BACKUP)
public int requestBackup(String[] packages, BackupObserver observer,
BackupManagerMonitor monitor, int flags) {
- return requestBackup(packages, observer, monitor, flags, OperationType.BACKUP);
- }
-
- /**
- * Request an immediate backup, providing an observer to which results of the backup operation
- * will be published. The Android backup system will decide for each package whether it will
- * be full app data backup or key/value-pair-based backup.
- *
- * <p>If this method returns {@link BackupManager#SUCCESS}, the OS will attempt to backup all
- * provided packages using the remote transport.
- *
- * @param packages List of package names to backup.
- * @param observer The {@link BackupObserver} to receive callbacks during the backup
- * operation. Could be {@code null}.
- * @param monitor The {@link BackupManagerMonitorWrapper} to receive callbacks of important
- * events during the backup operation. Could be {@code null}.
- * @param flags {@link #FLAG_NON_INCREMENTAL_BACKUP}.
- * @param operationType {@link OperationType}
- * @return {@link BackupManager#SUCCESS} on success; nonzero on error.
- * @throws IllegalArgumentException on null or empty {@code packages} param.
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.BACKUP)
- public int requestBackup(String[] packages, BackupObserver observer,
- BackupManagerMonitor monitor, int flags, @OperationType int operationType) {
checkServiceBinder();
if (sService != null) {
try {
@@ -860,8 +806,7 @@ public class BackupManager {
BackupManagerMonitorWrapper monitorWrapper = monitor == null
? null
: new BackupManagerMonitorWrapper(monitor);
- return sService.requestBackup(packages, observerWrapper, monitorWrapper, flags,
- operationType);
+ return sService.requestBackup(packages, observerWrapper, monitorWrapper, flags);
} catch (RemoteException e) {
Log.e(TAG, "requestBackup() couldn't connect");
}
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index f7ed6f1f2feb..3701ea825933 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -19,8 +19,10 @@ package android.app.backup;
import static android.app.backup.BackupManager.OperationType;
import android.annotation.Nullable;
+import android.annotation.StringDef;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.XmlResourceParser;
import android.os.ParcelFileDescriptor;
@@ -33,6 +35,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -93,6 +96,15 @@ public class FullBackup {
public static final String FLAG_REQUIRED_FAKE_CLIENT_SIDE_ENCRYPTION =
"fakeClientSideEncryption";
+ @StringDef({
+ ConfigSection.CLOUD_BACKUP,
+ ConfigSection.DEVICE_TRANSFER
+ })
+ private @interface ConfigSection {
+ String CLOUD_BACKUP = "cloud-backup";
+ String DEVICE_TRANSFER = "device-transfer";
+ }
+
/**
* Identify {@link BackupScheme} object by package and operation type
* (see {@link OperationType}) it corresponds to.
@@ -273,6 +285,7 @@ public class FullBackup {
private final static String TAG_INCLUDE = "include";
private final static String TAG_EXCLUDE = "exclude";
+ final int mDataExtractionRules;
final int mFullBackupContent;
@OperationType final int mOperationType;
final PackageManager mPackageManager;
@@ -394,7 +407,10 @@ public class FullBackup {
ArraySet<PathWithRequiredFlags> mExcludes;
BackupScheme(Context context, @OperationType int operationType) {
- mFullBackupContent = context.getApplicationInfo().fullBackupContent;
+ ApplicationInfo applicationInfo = context.getApplicationInfo();
+
+ mDataExtractionRules = applicationInfo.dataExtractionRulesRes;
+ mFullBackupContent = applicationInfo.fullBackupContent;
mOperationType = operationType;
mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
mPackageManager = context.getPackageManager();
@@ -468,34 +484,98 @@ public class FullBackup {
mIncludes = new ArrayMap<String, Set<PathWithRequiredFlags>>();
mExcludes = new ArraySet<PathWithRequiredFlags>();
- if (mFullBackupContent == 0) {
- // android:fullBackupContent="true" which means that we'll do everything.
+ if (mFullBackupContent == 0 && mDataExtractionRules == 0) {
+ // No scheme specified via either new or legacy config, will copy everything.
if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
Log.v(FullBackup.TAG_XML_PARSER, "android:fullBackupContent - \"true\"");
}
} else {
- // android:fullBackupContent="@xml/some_resource".
+ // Scheme is present.
if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
- Log.v(FullBackup.TAG_XML_PARSER,
- "android:fullBackupContent - found xml resource");
+ Log.v(FullBackup.TAG_XML_PARSER, "Found xml scheme: "
+ + "android:fullBackupContent=" + mFullBackupContent
+ + "; android:dataExtractionRules=" + mDataExtractionRules);
}
- XmlResourceParser parser = null;
+
try {
- parser = mPackageManager
- .getResourcesForApplication(mPackageName)
- .getXml(mFullBackupContent);
- parseBackupSchemeFromXmlLocked(parser, mExcludes, mIncludes);
+ parseSchemeForOperationType(mOperationType);
} catch (PackageManager.NameNotFoundException e) {
// Throw it as an IOException
throw new IOException(e);
- } finally {
- if (parser != null) {
- parser.close();
- }
}
}
}
+ private void parseSchemeForOperationType(@OperationType int operationType)
+ throws PackageManager.NameNotFoundException, IOException, XmlPullParserException {
+ String configSection = getConfigSectionForOperationType(operationType);
+ if (configSection == null) {
+ Slog.w(TAG, "Given operation type isn't supported by backup scheme: "
+ + operationType);
+ return;
+ }
+
+ if (mDataExtractionRules != 0) {
+ // New config is present. Use it if it has configuration for this operation
+ // type.
+ try (XmlResourceParser parser = getParserForResource(mDataExtractionRules)) {
+ parseNewBackupSchemeFromXmlLocked(parser, configSection, mExcludes, mIncludes);
+ }
+ if (!mExcludes.isEmpty() || !mIncludes.isEmpty()) {
+ // Found configuration in the new config, we will use it.
+ return;
+ }
+ }
+
+ // TODO(b/180523564): Ignore the old config for apps targeting Android S+ during D2D.
+
+ if (mFullBackupContent != 0) {
+ // Fall back to the old config.
+ try (XmlResourceParser parser = getParserForResource(mFullBackupContent)) {
+ parseBackupSchemeFromXmlLocked(parser, mExcludes, mIncludes);
+ }
+ }
+ }
+
+ @Nullable
+ private String getConfigSectionForOperationType(@OperationType int operationType) {
+ switch (operationType) {
+ case OperationType.BACKUP:
+ return ConfigSection.CLOUD_BACKUP;
+ case OperationType.MIGRATION:
+ return ConfigSection.DEVICE_TRANSFER;
+ default:
+ return null;
+ }
+ }
+
+ private XmlResourceParser getParserForResource(int resourceId)
+ throws PackageManager.NameNotFoundException {
+ return mPackageManager
+ .getResourcesForApplication(mPackageName)
+ .getXml(resourceId);
+ }
+
+ private void parseNewBackupSchemeFromXmlLocked(XmlPullParser parser,
+ @ConfigSection String configSection,
+ Set<PathWithRequiredFlags> excludes,
+ Map<String, Set<PathWithRequiredFlags>> includes)
+ throws IOException, XmlPullParserException {
+ verifyTopLevelTag(parser, "data-extraction-rules");
+
+ int event;
+ while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (event != XmlPullParser.START_TAG || !configSection.equals(parser.getName())) {
+ continue;
+ }
+
+ // TODO(b/180523028): Parse required attributes for rules (e.g. encryption).
+ parseRules(parser, excludes, includes, Optional.of(0), configSection);
+ }
+
+ logParsingResults(excludes, includes);
+ }
+
@VisibleForTesting
public void parseBackupSchemeFromXmlLocked(XmlPullParser parser,
Set<PathWithRequiredFlags> excludes,
@@ -503,7 +583,7 @@ public class FullBackup {
throws IOException, XmlPullParserException {
verifyTopLevelTag(parser, "full-backup-content");
- parseRules(parser, excludes, includes, Optional.empty());
+ parseRules(parser, excludes, includes, Optional.empty(), "full-backup-content");
logParsingResults(excludes, includes);
}
@@ -532,10 +612,12 @@ public class FullBackup {
private void parseRules(XmlPullParser parser,
Set<PathWithRequiredFlags> excludes,
Map<String, Set<PathWithRequiredFlags>> includes,
- Optional<Integer> maybeRequiredFlags)
+ Optional<Integer> maybeRequiredFlags,
+ String endingTag)
throws IOException, XmlPullParserException {
int event;
- while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ while ((event = parser.next()) != XmlPullParser.END_DOCUMENT
+ && !parser.getName().equals(endingTag)) {
switch (event) {
case XmlPullParser.START_TAG:
validateInnerTagContents(parser);
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index e1bbc08e72f3..bf5be95c4ab0 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -547,11 +547,9 @@ interface IBackupManager {
* set can be restored.
* @param transportID The name of the transport to use for the restore operation.
* May be null, in which case the current active transport is used.
- * @param operationType Type of the operation, see {@link BackupManager#OperationType}
* @return An interface to the restore session, or null on error.
*/
- IRestoreSession beginRestoreSessionForUser(int userId, String packageName, String transportID,
- int operationType);
+ IRestoreSession beginRestoreSessionForUser(int userId, String packageName, String transportID);
/**
* Notify the backup manager that a BackupAgent has completed the operation
@@ -680,7 +678,7 @@ interface IBackupManager {
* {@link android.app.backup.IBackupManager.requestBackupForUser} for the calling user id.
*/
int requestBackup(in String[] packages, IBackupObserver observer, IBackupManagerMonitor monitor,
- int flags, int operationType);
+ int flags);
/**
* Cancel all running backups. After this call returns, no currently running backups will
diff --git a/core/java/android/app/people/PeopleSpaceTile.java b/core/java/android/app/people/PeopleSpaceTile.java
index 9a53b99aaefe..132af4b2f67b 100644
--- a/core/java/android/app/people/PeopleSpaceTile.java
+++ b/core/java/android/app/people/PeopleSpaceTile.java
@@ -53,6 +53,7 @@ public class PeopleSpaceTile implements Parcelable {
private boolean mIsImportantConversation;
private String mNotificationKey;
private CharSequence mNotificationContent;
+ private String mNotificationCategory;
private Uri mNotificationDataUri;
private Intent mIntent;
private long mNotificationTimestamp;
@@ -70,6 +71,7 @@ public class PeopleSpaceTile implements Parcelable {
mIsImportantConversation = b.mIsImportantConversation;
mNotificationKey = b.mNotificationKey;
mNotificationContent = b.mNotificationContent;
+ mNotificationCategory = b.mNotificationCategory;
mNotificationDataUri = b.mNotificationDataUri;
mIntent = b.mIntent;
mNotificationTimestamp = b.mNotificationTimestamp;
@@ -129,6 +131,10 @@ public class PeopleSpaceTile implements Parcelable {
return mNotificationContent;
}
+ public String getNotificationCategory() {
+ return mNotificationCategory;
+ }
+
public Uri getNotificationDataUri() {
return mNotificationDataUri;
}
@@ -166,6 +172,7 @@ public class PeopleSpaceTile implements Parcelable {
builder.setIsImportantConversation(mIsImportantConversation);
builder.setNotificationKey(mNotificationKey);
builder.setNotificationContent(mNotificationContent);
+ builder.setNotificationCategory(mNotificationCategory);
builder.setNotificationDataUri(mNotificationDataUri);
builder.setIntent(mIntent);
builder.setNotificationTimestamp(mNotificationTimestamp);
@@ -186,6 +193,7 @@ public class PeopleSpaceTile implements Parcelable {
private boolean mIsImportantConversation;
private String mNotificationKey;
private CharSequence mNotificationContent;
+ private String mNotificationCategory;
private Uri mNotificationDataUri;
private Intent mIntent;
private long mNotificationTimestamp;
@@ -299,6 +307,12 @@ public class PeopleSpaceTile implements Parcelable {
return this;
}
+ /** Sets the associated notification's category. */
+ public Builder setNotificationCategory(String notificationCategory) {
+ mNotificationCategory = notificationCategory;
+ return this;
+ }
+
/** Sets the associated notification's data URI. */
public Builder setNotificationDataUri(Uri notificationDataUri) {
mNotificationDataUri = notificationDataUri;
@@ -342,6 +356,7 @@ public class PeopleSpaceTile implements Parcelable {
mIsImportantConversation = in.readBoolean();
mNotificationKey = in.readString();
mNotificationContent = in.readCharSequence();
+ mNotificationCategory = in.readString();
mNotificationDataUri = in.readParcelable(Uri.class.getClassLoader());
mIntent = in.readParcelable(Intent.class.getClassLoader());
mNotificationTimestamp = in.readLong();
@@ -367,6 +382,7 @@ public class PeopleSpaceTile implements Parcelable {
dest.writeBoolean(mIsImportantConversation);
dest.writeString(mNotificationKey);
dest.writeCharSequence(mNotificationContent);
+ dest.writeString(mNotificationCategory);
dest.writeParcelable(mNotificationDataUri, flags);
dest.writeParcelable(mIntent, flags);
dest.writeLong(mNotificationTimestamp);
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 4277292e19a3..fc54c716d4ec 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -40,6 +40,7 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -92,7 +93,10 @@ public class AppWidgetHostView extends FrameLayout {
int mLayoutId = -1;
private InteractionHandler mInteractionHandler;
private boolean mOnLightBackground;
- PointF mCurrentSize = null;
+ private PointF mCurrentSize = null;
+ private RemoteViews.ColorResources mColorResources = null;
+ // Stores the last remote views last inflated.
+ private RemoteViews mLastInflatedRemoteViews = null;
private Executor mAsyncExecutor;
private CancellationSignal mLastExecutionSignal;
@@ -358,7 +362,7 @@ public class AppWidgetHostView extends FrameLayout {
PointF newSize = new PointF(size.x - xPaddingDips, size.y - yPaddingDips);
if (!newSize.equals(mCurrentSize)) {
mCurrentSize = newSize;
- mLayoutId = -1; // Prevents recycling the view.
+ reapplyLastRemoteViews();
}
}
@@ -368,7 +372,7 @@ public class AppWidgetHostView extends FrameLayout {
public void clearCurrentSize() {
if (mCurrentSize != null) {
mCurrentSize = null;
- mLayoutId = -1;
+ reapplyLastRemoteViews();
}
}
@@ -477,10 +481,18 @@ public class AppWidgetHostView extends FrameLayout {
* AppWidget provider. Will animate into these new views as needed
*/
public void updateAppWidget(RemoteViews remoteViews) {
+ this.mLastInflatedRemoteViews = remoteViews;
applyRemoteViews(remoteViews, true);
}
/**
+ * Reapply the last inflated remote views, or the default view is none was inflated.
+ */
+ private void reapplyLastRemoteViews() {
+ applyRemoteViews(mLastInflatedRemoteViews, true);
+ }
+
+ /**
* @hide
*/
protected void applyRemoteViews(RemoteViews remoteViews, boolean useAsyncIfPossible) {
@@ -518,7 +530,8 @@ public class AppWidgetHostView extends FrameLayout {
// layout matches, try recycling it
if (content == null && layoutId == mLayoutId) {
try {
- remoteViews.reapply(mContext, mView, mInteractionHandler);
+ remoteViews.reapply(mContext, mView, mInteractionHandler, mCurrentSize,
+ mColorResources);
content = mView;
recycled = true;
if (LOGD) Log.d(TAG, "was able to recycle existing layout");
@@ -530,7 +543,8 @@ public class AppWidgetHostView extends FrameLayout {
// Try normal RemoteView inflation
if (content == null) {
try {
- content = remoteViews.apply(mContext, this, mInteractionHandler, mCurrentSize);
+ content = remoteViews.apply(mContext, this, mInteractionHandler,
+ mCurrentSize, mColorResources);
if (LOGD) Log.d(TAG, "had to inflate new layout");
} catch (RuntimeException e) {
exception = e;
@@ -583,7 +597,8 @@ public class AppWidgetHostView extends FrameLayout {
mAsyncExecutor,
new ViewApplyListener(remoteViews, layoutId, true),
mInteractionHandler,
- mCurrentSize);
+ mCurrentSize,
+ mColorResources);
} catch (Exception e) {
// Reapply failed. Try apply
}
@@ -594,7 +609,8 @@ public class AppWidgetHostView extends FrameLayout {
mAsyncExecutor,
new ViewApplyListener(remoteViews, layoutId, false),
mInteractionHandler,
- mCurrentSize);
+ mCurrentSize,
+ mColorResources);
}
}
@@ -662,9 +678,13 @@ public class AppWidgetHostView extends FrameLayout {
protected Context getRemoteContext() {
try {
// Return if cloned successfully, otherwise default
- return mContext.createApplicationContext(
+ Context newContext = mContext.createApplicationContext(
mInfo.providerInfo.applicationInfo,
Context.CONTEXT_RESTRICTED);
+ if (mColorResources != null) {
+ mColorResources.apply(newContext);
+ }
+ return newContext;
} catch (NameNotFoundException e) {
Log.e(TAG, "Package name " + mInfo.providerInfo.packageName + " not found");
return mContext;
@@ -819,4 +839,37 @@ public class AppWidgetHostView extends FrameLayout {
}
};
}
+
+ /**
+ * Set the dynamically overloaded color resources.
+ *
+ * {@code colorMapping} maps a predefined set of color resources to their ARGB
+ * representation. Any entry not in the predefined set of colors will be ignored.
+ *
+ * Calling this method will trigger a full re-inflation of the App Widget.
+ *
+ * The color resources that can be overloaded are the ones whose name is prefixed with
+ * {@code system_primary_}, {@code system_secondary_} or {@code system_neutral_}, for example
+ * {@link android.R.color#system_primary_500}.
+ */
+ public void setColorResources(@NonNull SparseIntArray colorMapping) {
+ mColorResources = RemoteViews.ColorResources.create(mContext, colorMapping);
+ mLayoutId = -1;
+ reapplyLastRemoteViews();
+ }
+
+ /**
+ * Reset the dynamically overloaded resources, reverting to the default values for
+ * all the colors.
+ *
+ * If colors were defined before, calling this method will trigger a full re-inflation of the
+ * App Widget.
+ */
+ public void resetColorResources() {
+ if (mColorResources != null) {
+ mColorResources = null;
+ mLayoutId = -1;
+ reapplyLastRemoteViews();
+ }
+ }
}
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index aac8710e8691..38919f61d9df 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -23,6 +23,8 @@ import android.annotation.RequiresFeature;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemService;
+import android.annotation.TestApi;
+import android.annotation.UserIdInt;
import android.app.IServiceConnection;
import android.app.PendingIntent;
import android.compat.annotation.UnsupportedAppUsage;
@@ -1095,7 +1097,9 @@ public class AppWidgetManager {
*
* @hide
*/
- public void setBindAppWidgetPermission(String packageName, int userId, boolean permission) {
+ @TestApi
+ public void setBindAppWidgetPermission(
+ @NonNull String packageName, @UserIdInt int userId, boolean permission) {
if (mService == null) {
return;
}
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index d893a5e49aa9..6ac1c1ae61ec 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -332,12 +332,13 @@ public class AppWidgetProviderInfo implements Parcelable {
/**
* Resource id for the description of the AppWidget.
+ *
* <p>This field corresponds to the <code>android:description</code> attribute in the AppWidget
* meta-data file.
*/
@SuppressLint("MutableBareField")
@IdRes
- public int descriptionResource;
+ public int descriptionRes;
/**
* Flags indicating various features supported by the widget. These are hints to the widget
@@ -385,7 +386,7 @@ public class AppWidgetProviderInfo implements Parcelable {
this.widgetCategory = in.readInt();
this.providerInfo = in.readTypedObject(ActivityInfo.CREATOR);
this.widgetFeatures = in.readInt();
- this.descriptionResource = in.readInt();
+ this.descriptionRes = in.readInt();
}
/**
@@ -442,14 +443,22 @@ public class AppWidgetProviderInfo implements Parcelable {
return loadDrawable(context, density, previewImage, false);
}
- /** Loads localized description for the app widget. */
+ /**
+ * Loads localized description for the app widget.
+ *
+ * <p>Description is intended to be displayed in the UI of the widget picker.
+ *
+ * @param context Context for accessing resources.
+ *
+ * @return CharSequence for app widget description for the current locale.
+ */
@Nullable
- public final String loadDescription(@NonNull Context context) {
- if (ResourceId.isValid(descriptionResource)) {
+ public final CharSequence loadDescription(@NonNull Context context) {
+ if (ResourceId.isValid(descriptionRes)) {
return context.getPackageManager()
.getText(
providerInfo.packageName,
- descriptionResource,
+ descriptionRes,
providerInfo.applicationInfo)
.toString()
.trim();
@@ -499,7 +508,7 @@ public class AppWidgetProviderInfo implements Parcelable {
out.writeInt(this.widgetCategory);
out.writeTypedObject(this.providerInfo, flags);
out.writeInt(this.widgetFeatures);
- out.writeInt(this.descriptionResource);
+ out.writeInt(this.descriptionRes);
}
@Override
@@ -528,7 +537,7 @@ public class AppWidgetProviderInfo implements Parcelable {
that.widgetCategory = this.widgetCategory;
that.providerInfo = this.providerInfo;
that.widgetFeatures = this.widgetFeatures;
- that.descriptionResource = this.descriptionResource;
+ that.descriptionRes = this.descriptionRes;
return that;
}
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index cd91aa9b16b7..53aaae0470e2 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -943,12 +943,13 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public boolean setBufferMillis(@BluetoothCodecConfig.SourceCodecType int codec, int value) {
- if (VDBG) log("setBufferMillis(" + codec + ", " + value + ")");
+ public boolean setBufferLengthMillis(@BluetoothCodecConfig.SourceCodecType int codec,
+ int value) {
+ if (VDBG) log("setBufferLengthMillis(" + codec + ", " + value + ")");
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()) {
- return service.setBufferMillis(codec, value);
+ return service.setBufferLengthMillis(codec, value);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ec46da0dcf0e..8d4157259ff7 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3654,12 +3654,12 @@ public final class BluetoothAdapter {
}
@Override
- public void onDeviceDisconnected(BluetoothDevice device) {
+ public void onDeviceDisconnected(BluetoothDevice device, int hciReason) {
for (Map.Entry<BluetoothConnectionCallback, Executor> callbackExecutorEntry:
mBluetoothConnectionCallbackExecutorMap.entrySet()) {
BluetoothConnectionCallback callback = callbackExecutorEntry.getKey();
Executor executor = callbackExecutorEntry.getValue();
- executor.execute(() -> callback.onDeviceDisconnected(device));
+ executor.execute(() -> callback.onDeviceDisconnected(device, hciReason));
}
}
};
@@ -3764,8 +3764,155 @@ public final class BluetoothAdapter {
/**
* Callback triggered when a bluetooth device (classic or BLE) is disconnected
* @param device is the disconnected bluetooth device
+ * @param reason is the disconnect reason
*/
- public void onDeviceDisconnected(BluetoothDevice device) {}
+ public void onDeviceDisconnected(BluetoothDevice device, @DisconnectReason int reason) {}
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "REASON_" }, value = {
+ REASON_UNKNOWN,
+ REASON_LOCAL_REQUEST,
+ REASON_REMOTE_REQUEST,
+ REASON_LOCAL_ERROR,
+ REASON_REMOTE_ERROR,
+ REASON_TIMEOUT,
+ REASON_SECURITY,
+ REASON_SYSTEM_POLICY,
+ REASON_RESOURCE_LIMIT_REACHED,
+ REASON_CONNECTION_EXISTS,
+ REASON_BAD_PARAMETERS})
+ public @interface DisconnectReason {}
+
+ /**
+ * Indicates that the ACL disconnected due to an unknown reason.
+ */
+ public static final int REASON_UNKNOWN = 0;
+
+ /**
+ * Indicates that the ACL disconnected due to an explicit request from the local device.
+ * <p>
+ * Example cause: This is a normal disconnect reason, e.g., user/app initiates
+ * disconnection.
+ */
+ public static final int REASON_LOCAL_REQUEST = 1;
+
+ /**
+ * Indicates that the ACL disconnected due to an explicit request from the remote device.
+ * <p>
+ * Example cause: This is a normal disconnect reason, e.g., user/app initiates
+ * disconnection.
+ * <p>
+ * Example solution: The app can also prompt the user to check their remote device.
+ */
+ public static final int REASON_REMOTE_REQUEST = 2;
+
+ /**
+ * Generic disconnect reason indicating the ACL disconnected due to an error on the local
+ * device.
+ * <p>
+ * Example solution: Prompt the user to check their local device (e.g., phone, car
+ * headunit).
+ */
+ public static final int REASON_LOCAL_ERROR = 3;
+
+ /**
+ * Generic disconnect reason indicating the ACL disconnected due to an error on the remote
+ * device.
+ * <p>
+ * Example solution: Prompt the user to check their remote device (e.g., headset, car
+ * headunit, watch).
+ */
+ public static final int REASON_REMOTE_ERROR = 4;
+
+ /**
+ * Indicates that the ACL disconnected due to a timeout.
+ * <p>
+ * Example cause: remote device might be out of range.
+ * <p>
+ * Example solution: Prompt user to verify their remote device is on or in
+ * connection/pairing mode.
+ */
+ public static final int REASON_TIMEOUT = 5;
+
+ /**
+ * Indicates that the ACL disconnected due to link key issues.
+ * <p>
+ * Example cause: Devices are either unpaired or remote device is refusing our pairing
+ * request.
+ * <p>
+ * Example solution: Prompt user to unpair and pair again.
+ */
+ public static final int REASON_SECURITY = 6;
+
+ /**
+ * Indicates that the ACL disconnected due to the local device's system policy.
+ * <p>
+ * Example cause: privacy policy, power management policy, permissions, etc.
+ * <p>
+ * Example solution: Prompt the user to check settings, or check with their system
+ * administrator (e.g. some corp-managed devices do not allow OPP connection).
+ */
+ public static final int REASON_SYSTEM_POLICY = 7;
+
+ /**
+ * Indicates that the ACL disconnected due to resource constraints, either on the local
+ * device or the remote device.
+ * <p>
+ * Example cause: controller is busy, memory limit reached, maximum number of connections
+ * reached.
+ * <p>
+ * Example solution: The app should wait and try again. If still failing, prompt the user
+ * to disconnect some devices, or toggle Bluetooth on the local and/or the remote device.
+ */
+ public static final int REASON_RESOURCE_LIMIT_REACHED = 8;
+
+ /**
+ * Indicates that the ACL disconnected because another ACL connection already exists.
+ */
+ public static final int REASON_CONNECTION_EXISTS = 9;
+
+ /**
+ * Indicates that the ACL disconnected due to incorrect parameters passed in from the app.
+ * <p>
+ * Example solution: Change parameters and try again. If error persists, the app can report
+ * telemetry and/or log the error in a bugreport.
+ */
+ public static final int REASON_BAD_PARAMETERS = 10;
+
+ /**
+ * Returns human-readable strings corresponding to {@link DisconnectReason}.
+ */
+ public static String disconnectReasonText(@DisconnectReason int reason) {
+ switch (reason) {
+ case REASON_UNKNOWN:
+ return "Reason unknown";
+ case REASON_LOCAL_REQUEST:
+ return "Local request";
+ case REASON_REMOTE_REQUEST:
+ return "Remote request";
+ case REASON_LOCAL_ERROR:
+ return "Local error";
+ case REASON_REMOTE_ERROR:
+ return "Remote error";
+ case REASON_TIMEOUT:
+ return "Timeout";
+ case REASON_SECURITY:
+ return "Security";
+ case REASON_SYSTEM_POLICY:
+ return "System policy";
+ case REASON_RESOURCE_LIMIT_REACHED:
+ return "Resource constrained";
+ case REASON_CONNECTION_EXISTS:
+ return "Connection already exists";
+ case REASON_BAD_PARAMETERS:
+ return "Bad parameters";
+ default:
+ return "Unrecognized disconnect reason: " + reason;
+ }
+ }
}
/**
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index ff6cffb272a5..0312a2190a4b 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -18,7 +18,9 @@ package android.bluetooth;
import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -30,6 +32,7 @@ import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
/**
@@ -37,44 +40,60 @@ import java.util.List;
*
* @hide
*/
+@SystemApi
public final class BluetoothMapClient implements BluetoothProfile {
private static final String TAG = "BluetoothMapClient";
private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
+ /** @hide */
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED";
+ /** @hide */
public static final String ACTION_MESSAGE_RECEIVED =
"android.bluetooth.mapmce.profile.action.MESSAGE_RECEIVED";
/* Actions to be used for pending intents */
+ /** @hide */
public static final String ACTION_MESSAGE_SENT_SUCCESSFULLY =
"android.bluetooth.mapmce.profile.action.MESSAGE_SENT_SUCCESSFULLY";
+ /** @hide */
public static final String ACTION_MESSAGE_DELIVERED_SUCCESSFULLY =
"android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY";
/**
* Action to notify read status changed
+ *
+ * @hide
*/
public static final String ACTION_MESSAGE_READ_STATUS_CHANGED =
"android.bluetooth.mapmce.profile.action.MESSAGE_READ_STATUS_CHANGED";
/**
* Action to notify deleted status changed
+ *
+ * @hide
*/
public static final String ACTION_MESSAGE_DELETED_STATUS_CHANGED =
"android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED";
- /* Extras used in ACTION_MESSAGE_RECEIVED intent.
- * NOTE: HANDLE is only valid for a single session with the device. */
+ /**
+ * Extras used in ACTION_MESSAGE_RECEIVED intent.
+ * NOTE: HANDLE is only valid for a single session with the device.
+ */
+ /** @hide */
public static final String EXTRA_MESSAGE_HANDLE =
"android.bluetooth.mapmce.profile.extra.MESSAGE_HANDLE";
+ /** @hide */
public static final String EXTRA_MESSAGE_TIMESTAMP =
"android.bluetooth.mapmce.profile.extra.MESSAGE_TIMESTAMP";
+ /** @hide */
public static final String EXTRA_MESSAGE_READ_STATUS =
"android.bluetooth.mapmce.profile.extra.MESSAGE_READ_STATUS";
+ /** @hide */
public static final String EXTRA_SENDER_CONTACT_URI =
"android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_URI";
+ /** @hide */
public static final String EXTRA_SENDER_CONTACT_NAME =
"android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_NAME";
@@ -84,6 +103,8 @@ public final class BluetoothMapClient implements BluetoothProfile {
* Possible values are:
* true: deleted
* false: undeleted
+ *
+ * @hide
*/
public static final String EXTRA_MESSAGE_DELETED_STATUS =
"android.bluetooth.mapmce.profile.extra.MESSAGE_DELETED_STATUS";
@@ -93,24 +114,42 @@ public final class BluetoothMapClient implements BluetoothProfile {
* Possible values are:
* 0: failure
* 1: success
+ *
+ * @hide
*/
public static final String EXTRA_RESULT_CODE =
"android.bluetooth.device.extra.RESULT_CODE";
- /** There was an error trying to obtain the state */
+ /**
+ * There was an error trying to obtain the state
+ * @hide
+ */
public static final int STATE_ERROR = -1;
+ /** @hide */
public static final int RESULT_FAILURE = 0;
+ /** @hide */
public static final int RESULT_SUCCESS = 1;
- /** Connection canceled before completion. */
+ /**
+ * Connection canceled before completion.
+ * @hide
+ */
public static final int RESULT_CANCELED = 2;
-
+ /** @hide */
private static final int UPLOADING_FEATURE_BITMASK = 0x08;
- /** Parameters in setMessageStatus */
+ /*
+ * UNREAD, READ, UNDELETED, DELETED are passed as parameters
+ * to setMessageStatus to indicate the messages new state.
+ */
+
+ /** @hide */
public static final int UNREAD = 0;
+ /** @hide */
public static final int READ = 1;
+ /** @hide */
public static final int UNDELETED = 2;
+ /** @hide */
public static final int DELETED = 3;
private BluetoothAdapter mAdapter;
@@ -132,19 +171,12 @@ public final class BluetoothMapClient implements BluetoothProfile {
mProfileConnector.connect(context, listener);
}
- protected void finalize() throws Throwable {
- try {
- close();
- } finally {
- super.finalize();
- }
- }
-
/**
* Close the connection to the backing service.
* Other public functions of BluetoothMap will return default error
* results once close() has been called. Multiple invocations of close()
* are ok.
+ * @hide
*/
public void close() {
mProfileConnector.disconnect();
@@ -158,6 +190,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* Returns true if the specified Bluetooth device is connected.
* Returns false if not connected, or if this proxy object is not
* currently connected to the Map service.
+ * @hide
*/
public boolean isConnected(BluetoothDevice device) {
if (VDBG) Log.d(TAG, "isConnected(" + device + ")");
@@ -225,6 +258,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* Get the list of connected devices. Currently at most one.
*
* @return list of connected devices
+ * @hide
*/
@Override
public List<BluetoothDevice> getConnectedDevices() {
@@ -246,6 +280,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* Get the list of devices matching specified states. Currently at most one.
*
* @return list of matching devices
+ * @hide
*/
@Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
@@ -267,6 +302,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* Get connection state of device
*
* @return device connection state
+ * @hide
*/
@Override
public int getConnectionState(BluetoothDevice device) {
@@ -383,11 +419,44 @@ public final class BluetoothMapClient implements BluetoothProfile {
* Send an SMS message to either the contacts primary number or the telephone number specified.
*
* @param device Bluetooth device
+ * @param contacts Uri Collection of the contacts
+ * @param message Message to be sent
+ * @param sentIntent intent issued when message is sent
+ * @param deliveredIntent intent issued when message is delivered
+ * @return true if the message is enqueued, false on error
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.SEND_SMS)
+ public boolean sendMessage(@NonNull BluetoothDevice device, @NonNull Collection<Uri> contacts,
+ @NonNull String message, @Nullable PendingIntent sentIntent,
+ @Nullable PendingIntent deliveredIntent) {
+ if (DBG) Log.d(TAG, "sendMessage(" + device + ", " + contacts + ", " + message);
+ final IBluetoothMapClient service = getService();
+ if (service != null && isEnabled() && isValidDevice(device)) {
+ try {
+ return service.sendMessage(device, contacts.toArray(new Uri[contacts.size()]),
+ message, sentIntent, deliveredIntent);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Send a message.
+ *
+ * Send an SMS message to either the contacts primary number or the telephone number specified.
+ *
+ * @param device Bluetooth device
* @param contacts Uri[] of the contacts
* @param message Message to be sent
* @param sentIntent intent issued when message is sent
* @param deliveredIntent intent issued when message is delivered
* @return true if the message is enqueued, false on error
+ * @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean sendMessage(BluetoothDevice device, Uri[] contacts, String message,
@@ -410,6 +479,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
*
* @param device Bluetooth device
* @return true if the message is enqueued, false on error
+ * @hide
*/
public boolean getUnreadMessages(BluetoothDevice device) {
if (DBG) Log.d(TAG, "getUnreadMessages(" + device + ")");
@@ -431,6 +501,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @param device The Bluetooth device to get this value for.
* @return Returns true if the Uploading bit value in SDP record's
* MapSupportedFeatures field is set. False is returned otherwise.
+ * @hide
*/
public boolean isUploadingSupported(BluetoothDevice device) {
final IBluetoothMapClient service = getService();
@@ -457,7 +528,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* "read", <code>UNDELETED</code> for "undeleted", <code>DELETED</code> for
* "deleted", otherwise return error
* @return <code>true</code> if request has been sent, <code>false</code> on error
- *
+ * @hide
*/
@RequiresPermission(Manifest.permission.READ_SMS)
public boolean setMessageStatus(BluetoothDevice device, String handle, int status) {
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index c31b04e81456..201d6c495d98 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -186,6 +186,7 @@ public interface BluetoothProfile {
*
* @hide
*/
+ @SystemApi
int MAP_CLIENT = 18;
/**
diff --git a/core/java/android/bluetooth/BufferConstraints.java b/core/java/android/bluetooth/BufferConstraints.java
index 7e5ec1e78435..97d97232b7a6 100644
--- a/core/java/android/bluetooth/BufferConstraints.java
+++ b/core/java/android/bluetooth/BufferConstraints.java
@@ -90,7 +90,7 @@ public final class BufferConstraints implements Parcelable {
* @hide
*/
@SystemApi
- public @Nullable BufferConstraint getCodec(@BluetoothCodecConfig.SourceCodecType int codec) {
+ public @Nullable BufferConstraint forCodec(@BluetoothCodecConfig.SourceCodecType int codec) {
return mBufferConstraints.get(codec);
}
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 46d8900e59a1..230c985d1dc8 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -132,8 +132,11 @@ public abstract class ContentResolver implements ContentInterface {
public static final String SYNC_EXTRAS_ACCOUNT = "account";
/**
- * If this extra is set to true, the sync request will be scheduled
- * at the front of the sync request queue and without any delay
+ * If this extra is set to true, the sync request will be scheduled at the front of the
+ * sync request queue, but it is still subject to JobScheduler quota and throttling due to
+ * App Standby buckets.
+ *
+ * <p>This is different from {@link #SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB}.
*/
public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
@@ -145,6 +148,29 @@ public abstract class ContentResolver implements ContentInterface {
public static final String SYNC_EXTRAS_REQUIRE_CHARGING = "require_charging";
/**
+ * Run this sync operation as an "expedited job"
+ * (see {@link android.app.job.JobInfo.Builder#setExpedited(boolean)}).
+ * Normally (if this flag isn't specified), sync operations are executed as regular
+ * {@link android.app.job.JobService} jobs.
+ *
+ * <p> Because Expedited Jobs have various restrictions compared to regular jobs, this flag
+ * cannot be combined with certain other flags, otherwise an
+ * <code>IllegalArgumentException</code> will be thrown. Notably, because Expedited Jobs do not
+ * support various constraints, the following restriction apply:
+ * <ul>
+ * <li>Can't be used with {@link #SYNC_EXTRAS_REQUIRE_CHARGING}
+ * <li>Can't be used with {@link #SYNC_EXTRAS_EXPEDITED}
+ * <li>Can't be used on periodic syncs.
+ * <li>When an expedited-job-sync fails and a retry is scheduled, the retried sync will be
+ * scheduled as a regular job unless {@link #SYNC_EXTRAS_IGNORE_BACKOFF} is set.
+ * </ul>
+ *
+ * <p>This is different from {@link #SYNC_EXTRAS_EXPEDITED}.
+ */
+ @SuppressLint("IntentName")
+ public static final String SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB = "schedule_as_expedited_job";
+
+ /**
* @deprecated instead use
* {@link #SYNC_EXTRAS_MANUAL}
*/
@@ -3220,6 +3246,18 @@ public abstract class ContentResolver implements ContentInterface {
}
/**
+ * {@hide}
+ * Helper function to throw an <code>IllegalArgumentException</code> if any illegal
+ * extras were set for a sync scheduled as an expedited job.
+ *
+ * @param extras bundle to validate.
+ */
+ public static boolean hasInvalidScheduleAsEjExtras(Bundle extras) {
+ return extras.getBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING)
+ || extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED);
+ }
+
+ /**
* Specifies that a sync should be requested with the specified the account, authority,
* and extras at the given frequency. If there is already another periodic sync scheduled
* with the account, authority and extras then a new periodic sync won't be added, instead
@@ -3233,7 +3271,8 @@ public abstract class ContentResolver implements ContentInterface {
* Periodic syncs are not allowed to have any of {@link #SYNC_EXTRAS_DO_NOT_RETRY},
* {@link #SYNC_EXTRAS_IGNORE_BACKOFF}, {@link #SYNC_EXTRAS_IGNORE_SETTINGS},
* {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE},
- * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL} set to true.
+ * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL},
+ * {@link #SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB} set to true.
* If any are supplied then an {@link IllegalArgumentException} will be thrown.
*
* <p>This method requires the caller to hold the permission
@@ -3273,16 +3312,14 @@ public abstract class ContentResolver implements ContentInterface {
* @param extras bundle to validate.
*/
public static boolean invalidPeriodicExtras(Bundle extras) {
- if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)
+ return extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)
|| extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
|| extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)
|| extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
|| extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)
|| extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false)
- || extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
- return true;
- }
- return false;
+ || extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)
+ || extras.getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, false);
}
/**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 4284dc2117c5..f3a4e1f79955 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -370,6 +370,25 @@ public abstract class Context {
/*********** Hidden flags below this line ***********/
/**
+ * Flag for {@link #bindService}: allow the process hosting the target service to be treated
+ * as if it's as important as a perceptible app to the user and avoid the oom killer killing
+ * this process in low memory situations until there aren't any other processes left but the
+ * ones which are user-perceptible.
+ *
+ * @hide
+ */
+ public static final int BIND_ALMOST_PERCEPTIBLE = 0x000010000;
+
+ /**
+ * Flag for {@link #bindService}: allow the process hosting the target service to gain
+ * {@link ActivityManager#PROCESS_CAPABILITY_NETWORK}, which allows it be able
+ * to access network regardless of any power saving restrictions.
+ *
+ * @hide
+ */
+ public static final int BIND_ALLOW_NETWORK_ACCESS = 0x00020000;
+
+ /**
* Flag for {@link #bindService}: allow background foreground service starts from the bound
* service's process.
* This flag is only respected if the caller is holding
@@ -3118,8 +3137,18 @@ public abstract class Context {
*
* @throws SecurityException If the caller does not have permission to access the service
* or the service can not be found.
- * @throws IllegalStateException If the application is in a state where the service
- * can not be started (such as not in the foreground in a state when services are allowed).
+ * @throws IllegalStateException
+ * Before Android {@link android.os.Build.VERSION_CODES#S},
+ * if the application is in a state where the service
+ * can not be started (such as not in the foreground in a state when services are allowed),
+ * {@link IllegalStateException} was thrown.
+ * @throws android.app.BackgroundServiceStartNotAllowedException
+ * On Android {@link android.os.Build.VERSION_CODES#S} and later,
+ * if the application is in a state where the service
+ * can not be started (such as not in the foreground in a state when services are allowed),
+ * {@link android.app.BackgroundServiceStartNotAllowedException} is thrown
+ * This excemption extends {@link IllegalStateException}, so apps can
+ * use {@code catch (IllegalStateException)} to catch both.
*
* @see #stopService
* @see #bindService
@@ -3150,7 +3179,8 @@ public abstract class Context {
* @throws SecurityException If the caller does not have permission to access the service
* or the service can not be found.
*
- * @throws IllegalStateException If the caller app's targeting API is
+ * @throws android.app.ForegroundServiceStartNotAllowedException
+ * If the caller app's targeting API is
* {@link android.os.Build.VERSION_CODES#S} or later, and the foreground service is restricted
* from start due to background restriction.
*
@@ -6663,15 +6693,6 @@ public abstract class Context {
}
/**
- * Indicates if this context is a visual context such as {@link android.app.Activity} or
- * a context created from {@link #createWindowContext(int, Bundle)}.
- * @hide
- */
- public boolean isUiContext() {
- throw new RuntimeException("Not implemented. Must override in a subclass.");
- }
-
- /**
* Returns {@code true} if the context is a UI context which can access UI components such as
* {@link WindowManager}, {@link android.view.LayoutInflater LayoutInflater} or
* {@link android.app.WallpaperManager WallpaperManager}. Accessing UI components from non-UI
@@ -6683,12 +6704,16 @@ public abstract class Context {
* {@link #createWindowContext(int, Bundle)} or
* {@link android.inputmethodservice.InputMethodService InputMethodService}
* </p>
+ * <p>
+ * Note that even if it is allowed programmatically, it is not suggested to override this
+ * method to bypass {@link android.os.strictmode.IncorrectContextUseViolation} verification.
+ * </p>
*
* @see #getDisplay()
* @see #getSystemService(String)
* @see android.os.StrictMode.VmPolicy.Builder#detectIncorrectContextUse()
*/
- public static boolean isUiContext(@NonNull Context context) {
- return context.isUiContext();
+ public boolean isUiContext() {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
}
}
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index 858d1e498783..b1252fd0b21f 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -18,6 +18,7 @@ package android.content;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityManager.PendingIntentInfo;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.os.Handler;
@@ -60,6 +61,9 @@ public class IntentSender implements Parcelable {
private final IIntentSender mTarget;
IBinder mWhitelistToken;
+ // cached pending intent information
+ private @Nullable PendingIntentInfo mCachedInfo;
+
/**
* Exception thrown when trying to send through a PendingIntent that
* has been canceled or is otherwise no longer able to execute the request.
@@ -209,13 +213,7 @@ public class IntentSender implements Parcelable {
*/
@Deprecated
public String getTargetPackage() {
- try {
- return ActivityManager.getService()
- .getPackageForIntentSender(mTarget);
- } catch (RemoteException e) {
- // Should never happen.
- return null;
- }
+ return getCreatorPackage();
}
/**
@@ -228,13 +226,7 @@ public class IntentSender implements Parcelable {
* none associated with it.
*/
public String getCreatorPackage() {
- try {
- return ActivityManager.getService()
- .getPackageForIntentSender(mTarget);
- } catch (RemoteException e) {
- // Should never happen.
- return null;
- }
+ return getCachedInfo().getCreatorPackage();
}
/**
@@ -247,13 +239,7 @@ public class IntentSender implements Parcelable {
* none associated with it.
*/
public int getCreatorUid() {
- try {
- return ActivityManager.getService()
- .getUidForIntentSender(mTarget);
- } catch (RemoteException e) {
- // Should never happen.
- return -1;
- }
+ return getCachedInfo().getCreatorUid();
}
/**
@@ -268,14 +254,8 @@ public class IntentSender implements Parcelable {
* none associated with it.
*/
public UserHandle getCreatorUserHandle() {
- try {
- int uid = ActivityManager.getService()
- .getUidForIntentSender(mTarget);
- return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null;
- } catch (RemoteException e) {
- // Should never happen.
- return null;
- }
+ int uid = getCachedInfo().getCreatorUid();
+ return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null;
}
/**
@@ -384,4 +364,16 @@ public class IntentSender implements Parcelable {
public IntentSender(IBinder target) {
mTarget = IIntentSender.Stub.asInterface(target);
}
+
+ private PendingIntentInfo getCachedInfo() {
+ if (mCachedInfo == null) {
+ try {
+ mCachedInfo = ActivityManager.getService().getInfoForIntentSender(mTarget);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ return mCachedInfo;
+ }
}
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
index 9e568a40e0ee..e1e6f75d152f 100644
--- a/core/java/android/content/SyncRequest.java
+++ b/core/java/android/content/SyncRequest.java
@@ -17,6 +17,7 @@
package android.content;
import android.accounts.Account;
+import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Bundle;
@@ -58,6 +59,8 @@ public class SyncRequest implements Parcelable {
private final boolean mIsAuthority;
/** Sync should be run in lieu of other syncs. */
private final boolean mIsExpedited;
+ /** Sync sound be ran as an expedited job. */
+ private final boolean mIsScheduledAsExpeditedJob;
/**
* {@hide}
@@ -79,6 +82,14 @@ public class SyncRequest implements Parcelable {
/**
* {@hide}
+ * @return whether this sync is scheduled as an expedited job.
+ */
+ public boolean isScheduledAsExpeditedJob() {
+ return mIsScheduledAsExpeditedJob;
+ }
+
+ /**
+ * {@hide}
*
* @return account object for this sync.
* @throws IllegalArgumentException if this function is called for a request that targets a
@@ -149,6 +160,7 @@ public class SyncRequest implements Parcelable {
parcel.writeInt((mDisallowMetered ? 1 : 0));
parcel.writeInt((mIsAuthority ? 1 : 0));
parcel.writeInt((mIsExpedited? 1 : 0));
+ parcel.writeInt(mIsScheduledAsExpeditedJob ? 1 : 0);
parcel.writeParcelable(mAccountToSync, flags);
parcel.writeString(mAuthority);
}
@@ -161,6 +173,7 @@ public class SyncRequest implements Parcelable {
mDisallowMetered = (in.readInt() != 0);
mIsAuthority = (in.readInt() != 0);
mIsExpedited = (in.readInt() != 0);
+ mIsScheduledAsExpeditedJob = (in.readInt() != 0);
mAccountToSync = in.readParcelable(null);
mAuthority = in.readString();
}
@@ -174,6 +187,7 @@ public class SyncRequest implements Parcelable {
mIsPeriodic = (b.mSyncType == Builder.SYNC_TYPE_PERIODIC);
mIsAuthority = (b.mSyncTarget == Builder.SYNC_TARGET_ADAPTER);
mIsExpedited = b.mExpedited;
+ mIsScheduledAsExpeditedJob = b.mScheduleAsExpeditedJob;
mExtras = new Bundle(b.mCustomExtras);
// For now we merge the sync config extras & the custom extras into one bundle.
// TODO: pass the configuration extras through separately.
@@ -258,6 +272,11 @@ public class SyncRequest implements Parcelable {
*/
private boolean mRequiresCharging;
+ /**
+ * Whether the sync should be scheduled as an expedited job.
+ */
+ private boolean mScheduleAsExpeditedJob;
+
public Builder() {
}
@@ -309,7 +328,8 @@ public class SyncRequest implements Parcelable {
* {@link ContentResolver#SYNC_EXTRAS_INITIALIZE},
* {@link ContentResolver#SYNC_EXTRAS_FORCE},
* {@link ContentResolver#SYNC_EXTRAS_EXPEDITED},
- * {@link ContentResolver#SYNC_EXTRAS_MANUAL}
+ * {@link ContentResolver#SYNC_EXTRAS_MANUAL},
+ * {@link ContentResolver#SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB}
* set to true. If any are supplied then an <code>IllegalArgumentException</code> will
* be thrown.
*
@@ -500,6 +520,22 @@ public class SyncRequest implements Parcelable {
}
/**
+ * Convenience function for setting
+ * {@link ContentResolver#SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB}.
+ *
+ * <p> Not to be confused with {@link ContentResolver#SYNC_EXTRAS_EXPEDITED}.
+ *
+ * <p> Not valid for periodic syncs, expedited syncs, and syncs that require charging - an
+ * <code>IllegalArgumentException</code> will be thrown in {@link #build()}.
+ *
+ * @param scheduleAsExpeditedJob whether to schedule as an expedited job. Default false.
+ */
+ public @NonNull Builder setScheduleAsExpeditedJob(boolean scheduleAsExpeditedJob) {
+ mScheduleAsExpeditedJob = scheduleAsExpeditedJob;
+ return this;
+ }
+
+ /**
* Performs validation over the request and throws the runtime exception
* <code>IllegalArgumentException</code> if this validation fails.
*
@@ -507,11 +543,6 @@ public class SyncRequest implements Parcelable {
* builder.
*/
public SyncRequest build() {
- // Validate the extras bundle
- ContentResolver.validateSyncExtrasBundle(mCustomExtras);
- if (mCustomExtras == null) {
- mCustomExtras = new Bundle();
- }
// Combine builder extra flags into the config bundle.
mSyncConfigExtras = new Bundle();
if (mIgnoreBackoff) {
@@ -532,17 +563,35 @@ public class SyncRequest implements Parcelable {
if (mExpedited) {
mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
}
+ if (mScheduleAsExpeditedJob) {
+ mSyncConfigExtras.putBoolean(
+ ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, true);
+ }
if (mIsManual) {
mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
}
+
+ if (mCustomExtras == null) {
+ mCustomExtras = new Bundle();
+ }
+ // Validate the extras bundles
+ ContentResolver.validateSyncExtrasBundle(mCustomExtras);
+ // If this is a periodic sync ensure than invalid extras were not set.
if (mSyncType == SYNC_TYPE_PERIODIC) {
- // If this is a periodic sync ensure than invalid extras were not set.
if (ContentResolver.invalidPeriodicExtras(mCustomExtras) ||
ContentResolver.invalidPeriodicExtras(mSyncConfigExtras)) {
throw new IllegalArgumentException("Illegal extras were set");
}
}
+ // If this sync is scheduled as an EJ, ensure that invalid extras were not set.
+ if (mCustomExtras.getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB)
+ || mScheduleAsExpeditedJob) {
+ if (ContentResolver.hasInvalidScheduleAsEjExtras(mCustomExtras)
+ || ContentResolver.hasInvalidScheduleAsEjExtras(mSyncConfigExtras)) {
+ throw new IllegalArgumentException("Illegal extras were set");
+ }
+ }
// Ensure that a target for the sync has been set.
if (mSyncTarget == SYNC_TARGET_UNKNOWN) {
throw new IllegalArgumentException("Must specify an adapter with" +
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index dec2c3d7fe48..0aa1be94d279 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -136,6 +136,18 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public int fullBackupContent = 0;
/**
+ * Applications can set this attribute to an xml resource within their app where they specified
+ * the rules determining which files and directories can be copied from the device as part of
+ * backup or transfer operations.
+ *<p>
+ * Set from the {@link android.R.styleable#AndroidManifestApplication_dataExtractionRules}
+ * attribute in the manifest.
+ *
+ * @hide
+ */
+ public int dataExtractionRulesRes = 0;
+
+ /**
* <code>true</code> if the package is capable of presenting a unified interface representing
* multiple profiles.
* @hide
@@ -1520,6 +1532,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
pw.println(prefix + "fullBackupContent="
+ (fullBackupContent < 0 ? "false" : "true"));
}
+ if (dataExtractionRulesRes != 0) {
+ pw.println(prefix + "dataExtractionRules=@xml/" + dataExtractionRulesRes);
+ }
pw.println(prefix + "crossProfile=" + (crossProfile ? "true" : "false"));
if (networkSecurityConfigRes != 0) {
pw.println(prefix + "networkSecurityConfigRes=0x"
@@ -1749,6 +1764,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
uiOptions = orig.uiOptions;
backupAgentName = orig.backupAgentName;
fullBackupContent = orig.fullBackupContent;
+ dataExtractionRulesRes = orig.dataExtractionRulesRes;
crossProfile = orig.crossProfile;
networkSecurityConfigRes = orig.networkSecurityConfigRes;
category = orig.category;
@@ -1836,6 +1852,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeInt(descriptionRes);
dest.writeInt(uiOptions);
dest.writeInt(fullBackupContent);
+ dest.writeInt(dataExtractionRulesRes);
dest.writeBoolean(crossProfile);
dest.writeInt(networkSecurityConfigRes);
dest.writeInt(category);
@@ -1920,6 +1937,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
descriptionRes = source.readInt();
uiOptions = source.readInt();
fullBackupContent = source.readInt();
+ dataExtractionRulesRes = source.readInt();
crossProfile = source.readBoolean();
networkSecurityConfigRes = source.readInt();
category = source.readInt();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f9122b1f6c8b..9a3fbdcea9ff 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3601,7 +3601,7 @@ public abstract class PackageManager {
* 1 - IncFs v1, core features, no PerUid support. Optional in R.
* 2 - IncFs v2, PerUid support, fs-verity support. Required in S.
*
- * @see IncrementalManager#isFeatureEnabled and IncrementalManager#isV2()
+ * @see IncrementalManager#getVersion()
* @hide
*/
@SystemApi
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 7a01392a24e8..29edd405be6b 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -260,6 +260,8 @@ public interface ParsingPackage extends ParsingPackageRead {
ParsingPackage setFullBackupContent(int fullBackupContent);
+ ParsingPackage setDataExtractionRules(int dataExtractionRules);
+
ParsingPackage setHasDomainUrls(boolean hasDomainUrls);
ParsingPackage setIconRes(int iconRes);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index c1a93d8c2428..067787d725d9 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -334,6 +334,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
private int descriptionRes;
private int fullBackupContent;
+ private int dataExtractionRules;
private int iconRes;
private int installLocation = ParsingPackageUtils.PARSE_DEFAULT_INSTALL_LOCATION;
private int labelRes;
@@ -1015,6 +1016,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
appInfo.enabled = getBoolean(Booleans.ENABLED);
// appInfo.enabledSetting
appInfo.fullBackupContent = fullBackupContent;
+ appInfo.dataExtractionRulesRes = dataExtractionRules;
// TODO(b/135203078): See ParsingPackageImpl#getHiddenApiEnforcementPolicy
// appInfo.mHiddenApiPolicy
// appInfo.hiddenUntilInstalled
@@ -1163,6 +1165,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
dest.writeInt(this.compatibleWidthLimitDp);
dest.writeInt(this.descriptionRes);
dest.writeInt(this.fullBackupContent);
+ dest.writeInt(this.dataExtractionRules);
dest.writeInt(this.iconRes);
dest.writeInt(this.installLocation);
dest.writeInt(this.labelRes);
@@ -1284,6 +1287,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
this.compatibleWidthLimitDp = in.readInt();
this.descriptionRes = in.readInt();
this.fullBackupContent = in.readInt();
+ this.dataExtractionRules = in.readInt();
this.iconRes = in.readInt();
this.installLocation = in.readInt();
this.labelRes = in.readInt();
@@ -1808,6 +1812,11 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
}
@Override
+ public int getDataExtractionRules() {
+ return dataExtractionRules;
+ }
+
+ @Override
public int getIconRes() {
return iconRes;
}
@@ -2264,6 +2273,12 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
}
@Override
+ public ParsingPackageImpl setDataExtractionRules(int value) {
+ dataExtractionRules = value;
+ return this;
+ }
+
+ @Override
public ParsingPackageImpl setIconRes(int value) {
iconRes = value;
return this;
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index ff4cebdd1533..f7f3e19efdf3 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -587,6 +587,11 @@ public interface ParsingPackageRead extends Parcelable {
*/
int getFullBackupContent();
+ /**
+ * @see R.styleable#AndroidManifestApplication_dataExtractionRules
+ */
+ int getDataExtractionRules();
+
/** @see ApplicationInfo#PRIVATE_FLAG_HAS_DOMAIN_URLS */
boolean isHasDomainUrls();
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index b7aa30f00691..0c033fddf069 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -2168,6 +2168,8 @@ public class ParsingPackageUtils {
.setNetworkSecurityConfigRes(resId(R.styleable.AndroidManifestApplication_networkSecurityConfig, sa))
.setRoundIconRes(resId(R.styleable.AndroidManifestApplication_roundIcon, sa))
.setTheme(resId(R.styleable.AndroidManifestApplication_theme, sa))
+ .setDataExtractionRules(
+ resId(R.styleable.AndroidManifestApplication_dataExtractionRules, sa))
// Strings
.setClassLoaderName(string(R.styleable.AndroidManifestApplication_classLoader, sa))
.setRequiredAccountType(string(R.styleable.AndroidManifestApplication_requiredAccountType, sa))
diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java
index 76d50bdf414c..43ef33e1f420 100644
--- a/core/java/android/hardware/biometrics/BiometricConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricConstants.java
@@ -145,6 +145,12 @@ public interface BiometricConstants {
int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15;
/**
+ * Authentication cannot proceed because re-enrollment is required.
+ * @hide
+ */
+ int BIOMETRIC_ERROR_RE_ENROLL = 16;
+
+ /**
* This constant is only used by SystemUI. It notifies SystemUI that authentication was paused
* because the authentication attempt was unsuccessful.
* @hide
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
index eafcf529de62..4385b1dac7a0 100644
--- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -153,6 +153,12 @@ public interface BiometricFaceConstants {
int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15;
/**
+ * Authentication cannot proceed because re-enrollment is required.
+ * @hide
+ */
+ int BIOMETRIC_ERROR_RE_ENROLL = 16;
+
+ /**
* @hide
*/
int FACE_ERROR_VENDOR_BASE = 1000;
diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
index 01f0e71a7c33..30e24d2ec8db 100644
--- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
@@ -166,6 +166,12 @@ public interface BiometricFingerprintConstants {
public static final int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15;
/**
+ * Authentication cannot proceed because re-enrollment is required.
+ * @hide
+ */
+ int BIOMETRIC_ERROR_RE_ENROLL = 16;
+
+ /**
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index f9eecaec5bb2..ac6ba0a4ac58 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -378,9 +378,10 @@ public abstract class CameraDevice implements AutoCloseable {
* released, continuous repeating requests stopped and any pending
* multi-frame capture requests flushed.</p>
*
- * <p>Note that the CameraExtensionSession currently supports at most two
- * multi frame capture surface formats: ImageFormat.YUV_420_888 and
- * ImageFormat.JPEG. Clients must query the multi-frame capture format support using
+ * <p>Note that the CameraExtensionSession currently supports at most wo
+ * multi frame capture surface formats: ImageFormat.JPEG will be supported
+ * by all extensions and ImageFormat.YUV_420_888 may or may not be supported.
+ * Clients must query the multi-frame capture format support using
* {@link CameraExtensionCharacteristics#getExtensionSupportedSizes(int, int)}.
* For repeating requests CameraExtensionSession supports only
* {@link android.graphics.SurfaceTexture} as output. Clients can query the supported resolution
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index d3eb3779189b..6121cd260dc3 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -35,6 +35,7 @@ import android.util.Log;
import android.util.Pair;
import android.util.Size;
+import java.util.HashSet;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -153,12 +154,8 @@ public final class CameraExtensionCharacteristics {
mChars = chars;
}
- private static List<Size> generateSupportedSizes(List<SizeList> sizesList,
- Integer format,
- StreamConfigurationMap streamMap) {
- // Per API contract it is assumed that the extension is able to support all
- // camera advertised sizes for a given format in case it doesn't return
- // a valid non-empty size list.
+ private static ArrayList<Size> getSupportedSizes(List<SizeList> sizesList,
+ Integer format) {
ArrayList<Size> ret = new ArrayList<>();
if ((sizesList != null) && (!sizesList.isEmpty())) {
for (SizeList entry : sizesList) {
@@ -170,13 +167,36 @@ public final class CameraExtensionCharacteristics {
}
}
}
+
+ return ret;
+ }
+
+ private static List<Size> generateSupportedSizes(List<SizeList> sizesList,
+ Integer format,
+ StreamConfigurationMap streamMap) {
+ // Per API contract it is assumed that the extension is able to support all
+ // camera advertised sizes for a given format in case it doesn't return
+ // a valid non-empty size list.
+ ArrayList<Size> ret = getSupportedSizes(sizesList, format);
Size[] supportedSizes = streamMap.getOutputSizes(format);
- if (supportedSizes != null) {
+ if ((ret.isEmpty()) && (supportedSizes != null)) {
ret.addAll(Arrays.asList(supportedSizes));
}
return ret;
}
+ private static List<Size> generateJpegSupportedSizes(List<SizeList> sizesList,
+ StreamConfigurationMap streamMap) {
+ ArrayList<Size> extensionSizes = getSupportedSizes(sizesList, ImageFormat.YUV_420_888);
+ HashSet<Size> supportedSizes = extensionSizes.isEmpty() ? new HashSet<>(Arrays.asList(
+ streamMap.getOutputSizes(ImageFormat.YUV_420_888))) : new HashSet<>(extensionSizes);
+ HashSet<Size> supportedJpegSizes = new HashSet<>(Arrays.asList(streamMap.getOutputSizes(
+ ImageFormat.JPEG)));
+ supportedSizes.retainAll(supportedJpegSizes);
+
+ return new ArrayList<>(supportedSizes);
+ }
+
/**
* A per-process global camera extension manager instance, to track and
* initialize/release extensions depending on client activity.
@@ -488,8 +508,8 @@ public final class CameraExtensionCharacteristics {
* {@link StreamConfigurationMap#getOutputSizes}.</p>
*
* <p>Device-specific extensions currently support at most two
- * multi-frame capture surface formats, ImageFormat.YUV_420_888 or
- * ImageFormat.JPEG.</p>
+ * multi-frame capture surface formats. ImageFormat.JPEG will be supported by all
+ * extensions and ImageFormat.YUV_420_888 may or may not be supported.</p>
*
* @param extension the extension type
* @param format device-specific extension output format
@@ -526,14 +546,17 @@ public final class CameraExtensionCharacteristics {
format, streamMap);
} else if (format == ImageFormat.JPEG) {
extenders.second.init(mCameraId, mChars.getNativeMetadata());
- if (extenders.second.getCaptureProcessor() == null) {
+ if (extenders.second.getCaptureProcessor() != null) {
+ // The framework will perform the additional encoding pass on the
+ // processed YUV_420 buffers.
+ return generateJpegSupportedSizes(
+ extenders.second.getSupportedResolutions(), streamMap);
+ } else {
return generateSupportedSizes(null, format, streamMap);
}
-
- return new ArrayList<>();
+ } else {
+ throw new IllegalArgumentException("Unsupported format: " + format);
}
-
- throw new IllegalArgumentException("Unsupported format: " + format);
} finally {
unregisterClient(clientId);
}
diff --git a/core/java/android/hardware/camera2/CameraExtensionSession.java b/core/java/android/hardware/camera2/CameraExtensionSession.java
index 877dfbc49df2..e1b817768461 100644
--- a/core/java/android/hardware/camera2/CameraExtensionSession.java
+++ b/core/java/android/hardware/camera2/CameraExtensionSession.java
@@ -238,8 +238,10 @@ public abstract class CameraExtensionSession implements AutoCloseable {
* from the camera device, to produce a single high-quality output result.
*
* <p>Note that single capture requests currently do not support
- * client parameters. Settings included in the request will
- * be entirely overridden by the device-specific extension. </p>
+ * client parameters except for {@link CaptureRequest#JPEG_ORIENTATION orientation} and
+ * {@link CaptureRequest#JPEG_QUALITY quality} in case of ImageFormat.JPEG output target.
+ * The rest of the settings included in the request will be entirely overridden by
+ * the device-specific extension. </p>
*
* <p>The {@link CaptureRequest.Builder#addTarget} supports only one
* ImageFormat.YUV_420_888 or ImageFormat.JPEG target surface. {@link CaptureRequest}
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
new file mode 100644
index 000000000000..936734b0c711
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.impl;
+
+import android.annotation.NonNull;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.extension.CaptureBundle;
+import android.hardware.camera2.extension.ICaptureProcessorImpl;
+import android.media.Image;
+import android.media.Image.Plane;
+import android.media.ImageReader;
+import android.media.ImageWriter;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Surface;
+
+import java.nio.ByteBuffer;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+// Jpeg compress input YUV and queue back in the client target surface.
+public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl {
+ public final static String TAG = "CameraExtensionJpeg";
+ private final static int JPEG_QUEUE_SIZE = 1;
+ private final static int JPEG_DEFAULT_QUALITY = 100;
+ private final static int JPEG_DEFAULT_ROTATION = 0;
+
+ private final Handler mHandler;
+ private final HandlerThread mHandlerThread;
+ private final ICaptureProcessorImpl mProcessor;
+
+ private ImageReader mYuvReader = null;
+ private android.hardware.camera2.extension.Size mResolution = null;
+ private int mFormat = -1;
+ private Surface mOutputSurface = null;
+ private ImageWriter mOutputWriter = null;
+
+ private static final class JpegParameters {
+ public HashSet<Long> mTimeStamps = new HashSet<>();
+ public int mRotation = JPEG_DEFAULT_ROTATION; // CCW multiple of 90 degrees
+ public int mQuality = JPEG_DEFAULT_QUALITY; // [0..100]
+ }
+
+ private ConcurrentLinkedQueue<JpegParameters> mJpegParameters = new ConcurrentLinkedQueue<>();
+
+ public CameraExtensionJpegProcessor(@NonNull ICaptureProcessorImpl processor) {
+ mProcessor = processor;
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ }
+
+ public void close() {
+ mHandlerThread.quitSafely();
+
+ if (mOutputWriter != null) {
+ mOutputWriter.close();
+ mOutputWriter = null;
+ }
+
+ if (mYuvReader != null) {
+ mYuvReader.close();
+ mYuvReader = null;
+ }
+ }
+
+ private static JpegParameters getJpegParameters(List<CaptureBundle> captureBundles) {
+ JpegParameters ret = new JpegParameters();
+ if (!captureBundles.isEmpty()) {
+ // The quality and orientation settings must be equal for requests in a burst
+
+ Byte jpegQuality = captureBundles.get(0).captureResult.get(CaptureResult.JPEG_QUALITY);
+ if (jpegQuality != null) {
+ ret.mQuality = jpegQuality;
+ } else {
+ Log.w(TAG, "No jpeg quality set, using default: " + JPEG_DEFAULT_QUALITY);
+ }
+
+ Integer orientation = captureBundles.get(0).captureResult.get(
+ CaptureResult.JPEG_ORIENTATION);
+ if (orientation != null) {
+ ret.mRotation = orientation / 90;
+ } else {
+ Log.w(TAG, "No jpeg rotation set, using default: " + JPEG_DEFAULT_ROTATION);
+ }
+
+ for (CaptureBundle bundle : captureBundles) {
+ Long timeStamp = bundle.captureResult.get(CaptureResult.SENSOR_TIMESTAMP);
+ if (timeStamp != null) {
+ ret.mTimeStamps.add(timeStamp);
+ } else {
+ Log.e(TAG, "Capture bundle without valid sensor timestamp!");
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ /**
+ * Compresses a YCbCr image to jpeg, applying a crop and rotation.
+ * <p>
+ * The input is defined as a set of 3 planes of 8-bit samples, one plane for
+ * each channel of Y, Cb, Cr.<br>
+ * The Y plane is assumed to have the same width and height of the entire
+ * image.<br>
+ * The Cb and Cr planes are assumed to be downsampled by a factor of 2, to
+ * have dimensions (floor(width / 2), floor(height / 2)).<br>
+ * Each plane is specified by a direct java.nio.ByteBuffer, a pixel-stride,
+ * and a row-stride. So, the sample at coordinate (x, y) can be retrieved
+ * from byteBuffer[x * pixel_stride + y * row_stride].
+ * <p>
+ * The pre-compression transformation is applied as follows:
+ * <ol>
+ * <li>The image is cropped to the rectangle from (cropLeft, cropTop) to
+ * (cropRight - 1, cropBottom - 1). So, a cropping-rectangle of (0, 0) -
+ * (width, height) is a no-op.</li>
+ * <li>The rotation is applied counter-clockwise relative to the coordinate
+ * space of the image, so a CCW rotation will appear CW when the image is
+ * rendered in scanline order. Only rotations which are multiples of
+ * 90-degrees are suppored, so the parameter 'rot90' specifies which
+ * multiple of 90 to rotate the image.</li>
+ * </ol>
+ *
+ * @param width the width of the image to compress
+ * @param height the height of the image to compress
+ * @param yBuf the buffer containing the Y component of the image
+ * @param yPStride the stride between adjacent pixels in the same row in
+ * yBuf
+ * @param yRStride the stride between adjacent rows in yBuf
+ * @param cbBuf the buffer containing the Cb component of the image
+ * @param cbPStride the stride between adjacent pixels in the same row in
+ * cbBuf
+ * @param cbRStride the stride between adjacent rows in cbBuf
+ * @param crBuf the buffer containing the Cr component of the image
+ * @param crPStride the stride between adjacent pixels in the same row in
+ * crBuf
+ * @param crRStride the stride between adjacent rows in crBuf
+ * @param outBuf a direct java.nio.ByteBuffer to hold the compressed jpeg.
+ * This must have enough capacity to store the result, or an
+ * error code will be returned.
+ * @param outBufCapacity the capacity of outBuf
+ * @param quality the jpeg-quality (1-100) to use
+ * @param cropLeft left-edge of the bounds of the image to crop to before
+ * rotation
+ * @param cropTop top-edge of the bounds of the image to crop to before
+ * rotation
+ * @param cropRight right-edge of the bounds of the image to crop to before
+ * rotation
+ * @param cropBottom bottom-edge of the bounds of the image to crop to
+ * before rotation
+ * @param rot90 the multiple of 90 to rotate the image CCW (after cropping)
+ */
+ private static native int compressJpegFromYUV420pNative(
+ int width, int height,
+ ByteBuffer yBuf, int yPStride, int yRStride,
+ ByteBuffer cbBuf, int cbPStride, int cbRStride,
+ ByteBuffer crBuf, int crPStride, int crRStride,
+ ByteBuffer outBuf, int outBufCapacity,
+ int quality,
+ int cropLeft, int cropTop, int cropRight, int cropBottom,
+ int rot90);
+
+ public void process(List<CaptureBundle> captureBundle) throws RemoteException {
+ JpegParameters jpegParams = getJpegParameters(captureBundle);
+ try {
+ mJpegParameters.add(jpegParams);
+ mProcessor.process(captureBundle);
+ } catch (Exception e) {
+ mJpegParameters.remove(jpegParams);
+ throw e;
+ }
+ }
+
+ public void onOutputSurface(Surface surface, int format) throws RemoteException {
+ if (format != ImageFormat.JPEG) {
+ Log.e(TAG, "Unsupported output format: " + format);
+ return;
+ }
+ mOutputSurface = surface;
+ initializePipeline();
+ }
+
+ @Override
+ public void onResolutionUpdate(android.hardware.camera2.extension.Size size)
+ throws RemoteException {
+ mResolution = size;
+ initializePipeline();
+ }
+
+ public void onImageFormatUpdate(int format) throws RemoteException {
+ if (format != ImageFormat.YUV_420_888) {
+ Log.e(TAG, "Unsupported input format: " + format);
+ return;
+ }
+ mFormat = format;
+ initializePipeline();
+ }
+
+ private void initializePipeline() throws RemoteException {
+ if ((mFormat != -1) && (mOutputSurface != null) && (mResolution != null) &&
+ (mYuvReader == null)) {
+ // Jpeg/blobs are expected to be configured with (w*h)x1
+ mOutputWriter = ImageWriter.newInstance(mOutputSurface, 1 /*maxImages*/,
+ ImageFormat.JPEG, mResolution.width * mResolution.height, 1);
+ mYuvReader = ImageReader.newInstance(mResolution.width, mResolution.height, mFormat,
+ JPEG_QUEUE_SIZE);
+ mYuvReader.setOnImageAvailableListener(new YuvCallback(), mHandler);
+ mProcessor.onOutputSurface(mYuvReader.getSurface(), mFormat);
+ mProcessor.onResolutionUpdate(mResolution);
+ mProcessor.onImageFormatUpdate(mFormat);
+ }
+ }
+
+ @Override
+ public IBinder asBinder() {
+ throw new UnsupportedOperationException("Binder IPC not supported!");
+ }
+
+ private class YuvCallback implements ImageReader.OnImageAvailableListener {
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ Image yuvImage = null;
+ Image jpegImage = null;
+ try {
+ yuvImage = mYuvReader.acquireNextImage();
+ jpegImage = mOutputWriter.dequeueInputImage();
+ } catch (IllegalStateException e) {
+ if (yuvImage != null) {
+ yuvImage.close();
+ }
+ if (jpegImage != null) {
+ jpegImage.close();
+ }
+ Log.e(TAG, "Failed to acquire processed yuv image or jpeg image!");
+ return;
+ }
+
+ ByteBuffer jpegBuffer = jpegImage.getPlanes()[0].getBuffer();
+ jpegBuffer.clear();
+ // Jpeg/blobs are expected to be configured with (w*h)x1
+ int jpegCapacity = jpegImage.getWidth();
+
+ Plane lumaPlane = yuvImage.getPlanes()[0];
+ Plane crPlane = yuvImage.getPlanes()[1];
+ Plane cbPlane = yuvImage.getPlanes()[2];
+
+ Iterator<JpegParameters> jpegIter = mJpegParameters.iterator();
+ JpegParameters jpegParams = null;
+ while(jpegIter.hasNext()) {
+ JpegParameters currentParams = jpegIter.next();
+ if (currentParams.mTimeStamps.contains(yuvImage.getTimestamp())) {
+ jpegParams = currentParams;
+ jpegIter.remove();
+ break;
+ }
+ }
+ if (jpegParams == null) {
+ if (mJpegParameters.isEmpty()) {
+ Log.w(TAG, "Empty jpeg settings queue! Using default jpeg orientation"
+ + " and quality!");
+ jpegParams = new JpegParameters();
+ jpegParams.mRotation = JPEG_DEFAULT_ROTATION;
+ jpegParams.mQuality = JPEG_DEFAULT_QUALITY;
+ } else {
+ Log.w(TAG, "No jpeg settings found with matching timestamp for current"
+ + " processed input!");
+ Log.w(TAG, "Using values from the top of the queue!");
+ jpegParams = mJpegParameters.poll();
+ }
+ }
+
+ compressJpegFromYUV420pNative(
+ yuvImage.getWidth(), yuvImage.getHeight(),
+ lumaPlane.getBuffer(), lumaPlane.getPixelStride(), lumaPlane.getRowStride(),
+ crPlane.getBuffer(), crPlane.getPixelStride(), crPlane.getRowStride(),
+ cbPlane.getBuffer(), cbPlane.getPixelStride(), cbPlane.getRowStride(),
+ jpegBuffer, jpegCapacity, jpegParams.mQuality,
+ 0, 0, yuvImage.getWidth(), yuvImage.getHeight(),
+ jpegParams.mRotation);
+ yuvImage.close();
+
+ try {
+ mOutputWriter.queueInputImage(jpegImage);
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Failed to queue encoded result!");
+ } finally {
+ jpegImage.close();
+ }
+ }
+ }
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 8451dedb6c37..0a561716d076 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -91,6 +91,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
private ImageReader mStubCaptureImageReader = null;
private ImageWriter mRepeatingRequestImageWriter = null;
+ private CameraExtensionJpegProcessor mImageJpegProcessor = null;
private ICaptureProcessorImpl mImageProcessor = null;
private CameraExtensionForwardProcessor mPreviewImageProcessor = null;
private IRequestUpdateProcessorImpl mPreviewRequestUpdateProcessor = null;
@@ -413,6 +414,10 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
if (mImageProcessor != null) {
if (mClientCaptureSurface != null) {
SurfaceInfo surfaceInfo = querySurface(mClientCaptureSurface);
+ if (surfaceInfo.mFormat == ImageFormat.JPEG) {
+ mImageJpegProcessor = new CameraExtensionJpegProcessor(mImageProcessor);
+ mImageProcessor = mImageJpegProcessor;
+ }
mBurstCaptureImageReader = ImageReader.newInstance(surfaceInfo.mWidth,
surfaceInfo.mHeight, CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT,
mImageExtender.getMaxCaptureStage());
@@ -570,14 +575,16 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
return null;
}
- // Set user supported jpeg quality and rotation parameters
+ // This will override the extension capture stage jpeg parameters with the user set
+ // jpeg quality and rotation. This will guarantee that client configured jpeg
+ // parameters always have highest priority.
Integer jpegRotation = clientRequest.get(CaptureRequest.JPEG_ORIENTATION);
if (jpegRotation != null) {
- requestBuilder.set(CaptureRequest.JPEG_ORIENTATION, jpegRotation);
+ captureStage.parameters.set(CaptureRequest.JPEG_ORIENTATION, jpegRotation);
}
Byte jpegQuality = clientRequest.get(CaptureRequest.JPEG_QUALITY);
if (jpegQuality != null) {
- requestBuilder.set(CaptureRequest.JPEG_QUALITY, jpegQuality);
+ captureStage.parameters.set(CaptureRequest.JPEG_QUALITY, jpegQuality);
}
requestBuilder.addTarget(target);
@@ -753,6 +760,11 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
mPreviewImageProcessor = null;
}
+ if (mImageJpegProcessor != null) {
+ mImageJpegProcessor.close();
+ mImageJpegProcessor = null;
+ }
+
mCaptureSession = null;
mImageProcessor = null;
mCameraRepeatingSurface = mClientRepeatingRequestSurface = null;
@@ -1014,7 +1026,10 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
mCaptureRequestMap.clear();
mCapturePendingMap.clear();
boolean processStatus = true;
- List<CaptureBundle> captureList = initializeParcelable(mCaptureStageMap);
+ Byte jpegQuality = mClientRequest.get(CaptureRequest.JPEG_QUALITY);
+ Integer jpegOrientation = mClientRequest.get(CaptureRequest.JPEG_ORIENTATION);
+ List<CaptureBundle> captureList = initializeParcelable(mCaptureStageMap,
+ jpegOrientation, jpegQuality);
try {
mImageProcessor.process(captureList);
} catch (RemoteException e) {
@@ -1444,10 +1459,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
}
for (int i = idx; i >= 0; i--) {
if (previewMap.valueAt(i).first != null) {
- Log.w(TAG, "Discard pending buffer with timestamp: " + previewMap.keyAt(i));
previewMap.valueAt(i).first.close();
} else {
- Log.w(TAG, "Discard pending result with timestamp: " + previewMap.keyAt(i));
if (mClientNotificationsEnabled && ((i != idx) || notifyCurrentIndex)) {
Log.w(TAG, "Preview frame drop with timestamp: " + previewMap.keyAt(i));
final long ident = Binder.clearCallingIdentity();
@@ -1639,7 +1652,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
}
private static List<CaptureBundle> initializeParcelable(
- HashMap<Integer, Pair<Image, TotalCaptureResult>> captureMap) {
+ HashMap<Integer, Pair<Image, TotalCaptureResult>> captureMap, Integer jpegOrientation,
+ Byte jpegQuality) {
ArrayList<CaptureBundle> ret = new ArrayList<>();
for (Integer stagetId : captureMap.keySet()) {
Pair<Image, TotalCaptureResult> entry = captureMap.get(stagetId);
@@ -1648,6 +1662,12 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
bundle.captureImage = initializeParcelImage(entry.first);
bundle.sequenceId = entry.second.getSequenceId();
bundle.captureResult = entry.second.getNativeMetadata();
+ if (jpegOrientation != null) {
+ bundle.captureResult.set(CaptureResult.JPEG_ORIENTATION, jpegOrientation);
+ }
+ if (jpegQuality != null) {
+ bundle.captureResult.set(CaptureResult.JPEG_QUALITY, jpegQuality);
+ }
ret.add(bundle);
}
diff --git a/core/java/android/hardware/display/DeviceProductInfo.java b/core/java/android/hardware/display/DeviceProductInfo.java
index 9457d8f1aac4..41126b70c89f 100644
--- a/core/java/android/hardware/display/DeviceProductInfo.java
+++ b/core/java/android/hardware/display/DeviceProductInfo.java
@@ -16,69 +16,40 @@
package android.hardware.display;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
import java.util.Objects;
/**
* Product-specific information about the display or the directly connected device on the
* display chain. For example, if the display is transitively connected, this field may contain
* product information about the intermediate device.
+ * @hide
*/
public final class DeviceProductInfo implements Parcelable {
- /** @hide */
- @IntDef(prefix = {"CONNECTION_TO_SINK_"}, value = {
- CONNECTION_TO_SINK_UNKNOWN,
- CONNECTION_TO_SINK_BUILT_IN,
- CONNECTION_TO_SINK_DIRECT,
- CONNECTION_TO_SINK_TRANSITIVE
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ConnectionToSinkType { }
-
- /** The device connection to the display sink is unknown. */
- public static final int CONNECTION_TO_SINK_UNKNOWN =
- IDeviceProductInfoConstants.CONNECTION_TO_SINK_UNKNOWN;
-
- /** The display sink is built-in to the device */
- public static final int CONNECTION_TO_SINK_BUILT_IN =
- IDeviceProductInfoConstants.CONNECTION_TO_SINK_BUILT_IN;
-
- /** The device is directly connected to the display sink. */
- public static final int CONNECTION_TO_SINK_DIRECT =
- IDeviceProductInfoConstants.CONNECTION_TO_SINK_DIRECT;
-
- /** The device is transitively connected to the display sink. */
- public static final int CONNECTION_TO_SINK_TRANSITIVE =
- IDeviceProductInfoConstants.CONNECTION_TO_SINK_TRANSITIVE;
-
private final String mName;
private final String mManufacturerPnpId;
private final String mProductId;
private final Integer mModelYear;
private final ManufactureDate mManufactureDate;
- private final @ConnectionToSinkType int mConnectionToSinkType;
+ private final int[] mRelativeAddress;
- /** @hide */
public DeviceProductInfo(
String name,
String manufacturerPnpId,
String productId,
Integer modelYear,
ManufactureDate manufactureDate,
- int connectionToSinkType) {
+ int[] relativeAddress) {
this.mName = name;
this.mManufacturerPnpId = manufacturerPnpId;
this.mProductId = productId;
this.mModelYear = modelYear;
this.mManufactureDate = manufactureDate;
- this.mConnectionToSinkType = connectionToSinkType;
+ this.mRelativeAddress = relativeAddress;
}
private DeviceProductInfo(Parcel in) {
@@ -87,13 +58,12 @@ public final class DeviceProductInfo implements Parcelable {
mProductId = (String) in.readValue(null);
mModelYear = (Integer) in.readValue(null);
mManufactureDate = (ManufactureDate) in.readValue(null);
- mConnectionToSinkType = in.readInt();
+ mRelativeAddress = in.createIntArray();
}
/**
* @return Display name.
*/
- @Nullable
public String getName() {
return mName;
}
@@ -101,7 +71,6 @@ public final class DeviceProductInfo implements Parcelable {
/**
* @return Manufacturer Plug and Play ID.
*/
- @NonNull
public String getManufacturerPnpId() {
return mManufacturerPnpId;
}
@@ -109,58 +78,32 @@ public final class DeviceProductInfo implements Parcelable {
/**
* @return Manufacturer product ID.
*/
- @NonNull
public String getProductId() {
return mProductId;
}
/**
- * @return Model year of the device. Return -1 if not available. Typically,
- * one of model year or manufacture year is available.
+ * @return Model year of the device. Typically exactly one of model year or
+ * manufacture date will be present.
*/
- public int getModelYear() {
- return mModelYear != null ? mModelYear : -1;
- }
-
- /**
- * @return The year of manufacture, or -1 it is not available. Typically,
- * one of model year or manufacture year is available.
- */
- public int getManufactureYear() {
- if (mManufactureDate == null) {
- return -1;
- }
- return mManufactureDate.mYear != null ? mManufactureDate.mYear : -1;
- }
-
- /**
- * @return The week of manufacture, or -1 it is not available. Typically,
- * not present if model year is available.
- */
- public int getManufactureWeek() {
- if (mManufactureDate == null) {
- return -1;
- }
- return mManufactureDate.mWeek != null ? mManufactureDate.mWeek : -1;
+ public Integer getModelYear() {
+ return mModelYear;
}
/**
* @return Manufacture date. Typically exactly one of model year or manufacture
* date will be present.
- *
- * @hide
*/
public ManufactureDate getManufactureDate() {
return mManufactureDate;
}
/**
- * @return How the current device is connected to the display sink. For example, the display
- * can be connected immediately to the device or there can be a receiver in between.
+ * @return Relative address in the display network. For example, for HDMI connected devices this
+ * can be its physical address. Each component of the address is in the range [0, 255].
*/
- @ConnectionToSinkType
- public int getConnectionToSinkType() {
- return mConnectionToSinkType;
+ public int[] getRelativeAddress() {
+ return mRelativeAddress;
}
@Override
@@ -176,8 +119,8 @@ public final class DeviceProductInfo implements Parcelable {
+ mModelYear
+ ", manufactureDate="
+ mManufactureDate
- + ", connectionToSinkType="
- + mConnectionToSinkType
+ + ", relativeAddress="
+ + Arrays.toString(mRelativeAddress)
+ '}';
}
@@ -191,16 +134,16 @@ public final class DeviceProductInfo implements Parcelable {
&& Objects.equals(mProductId, that.mProductId)
&& Objects.equals(mModelYear, that.mModelYear)
&& Objects.equals(mManufactureDate, that.mManufactureDate)
- && mConnectionToSinkType == that.mConnectionToSinkType;
+ && Arrays.equals(mRelativeAddress, that.mRelativeAddress);
}
@Override
public int hashCode() {
return Objects.hash(mName, mManufacturerPnpId, mProductId, mModelYear, mManufactureDate,
- mConnectionToSinkType);
+ Arrays.hashCode(mRelativeAddress));
}
- @NonNull public static final Creator<DeviceProductInfo> CREATOR =
+ public static final Creator<DeviceProductInfo> CREATOR =
new Creator<DeviceProductInfo>() {
@Override
public DeviceProductInfo createFromParcel(Parcel in) {
@@ -219,13 +162,13 @@ public final class DeviceProductInfo implements Parcelable {
}
@Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
+ public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mName);
dest.writeString(mManufacturerPnpId);
dest.writeValue(mProductId);
dest.writeValue(mModelYear);
dest.writeValue(mManufactureDate);
- dest.writeInt(mConnectionToSinkType);
+ dest.writeIntArray(mRelativeAddress);
}
/**
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 48b05b7d9e15..2d58520a942e 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -67,12 +67,6 @@ public abstract class DisplayManagerInternal {
public abstract boolean isProximitySensorAvailable();
/**
- * Returns the id of the {@link com.android.server.display.DisplayGroup} to which the provided
- * display belongs.
- */
- public abstract int getDisplayGroupId(int displayId);
-
- /**
* Registers a display group listener which will be informed of the addition, removal, or change
* of display groups.
*
@@ -469,7 +463,7 @@ public abstract class DisplayManagerInternal {
void onStateChanged();
void onProximityPositive();
void onProximityNegative();
- void onDisplayStateChange(int state); // one of the Display state constants
+ void onDisplayStateChange(boolean allInactive, boolean allOff);
void acquireSuspendBlocker();
void releaseSuspendBlocker();
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index a9bcdeff7e47..f868a5066c25 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -831,6 +831,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
case BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED:
return context.getString(
com.android.internal.R.string.face_error_security_update_required);
+ case BIOMETRIC_ERROR_RE_ENROLL:
+ return context.getString(
+ com.android.internal.R.string.face_recalibrate_notification_content);
case FACE_ERROR_VENDOR: {
String[] msgArray = context.getResources().getStringArray(
com.android.internal.R.array.face_error_vendor);
@@ -1389,7 +1392,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
case FACE_ACQUIRED_PAN_TOO_EXTREME:
case FACE_ACQUIRED_TILT_TOO_EXTREME:
case FACE_ACQUIRED_ROLL_TOO_EXTREME:
- return context.getString(R.string.face_acquired_not_detected);
+ return context.getString(R.string.face_acquired_poor_gaze);
// Provide more detailed feedback for other soft errors.
case FACE_ACQUIRED_INSUFFICIENT:
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index eaa38f3e862c..4743fee3257b 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -25,6 +25,8 @@ import android.hardware.input.TouchCalibration;
import android.os.CombinedVibrationEffect;
import android.hardware.input.IInputSensorEventListener;
import android.hardware.input.InputSensorInfo;
+import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
import android.os.IBinder;
import android.os.IVibratorStateListener;
import android.os.VibrationEffect;
@@ -127,4 +129,14 @@ interface IInputManager {
void disableSensor(int deviceId, int sensorType);
boolean flushSensor(int deviceId, int sensorType);
+
+ List<Light> getLights(int deviceId);
+
+ LightState getLightState(int deviceId, int lightId);
+
+ void setLightStates(int deviceId, in int[] lightIds, in LightState[] states, in IBinder token);
+
+ void openLightSession(int deviceId, String opPkg, in IBinder token);
+
+ void closeLightSession(int deviceId, in IBinder token);
}
diff --git a/core/java/android/hardware/input/InputDeviceLightsManager.java b/core/java/android/hardware/input/InputDeviceLightsManager.java
new file mode 100644
index 000000000000..a3b91a99fdb7
--- /dev/null
+++ b/core/java/android/hardware/input/InputDeviceLightsManager.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input;
+
+import android.annotation.NonNull;
+import android.app.ActivityThread;
+import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
+import android.hardware.lights.LightsManager;
+import android.hardware.lights.LightsRequest;
+import android.util.CloseGuard;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.ref.Reference;
+import java.util.List;
+
+/**
+ * LightsManager manages an input device's lights {@link android.hardware.input.Light}.
+ */
+class InputDeviceLightsManager extends LightsManager {
+ private static final String TAG = "InputDeviceLightsManager";
+ private static final boolean DEBUG = false;
+
+ private final InputManager mInputManager;
+
+ // The input device ID.
+ private final int mDeviceId;
+ // Package name
+ private final String mPackageName;
+
+ InputDeviceLightsManager(InputManager inputManager, int deviceId) {
+ super(ActivityThread.currentActivityThread().getSystemContext());
+ mInputManager = inputManager;
+ mDeviceId = deviceId;
+ mPackageName = ActivityThread.currentPackageName();
+ }
+
+ /**
+ * Returns the lights available on the device.
+ *
+ * @return A list of available lights
+ */
+ @Override
+ public @NonNull List<Light> getLights() {
+ return mInputManager.getLights(mDeviceId);
+ }
+
+ /**
+ * Returns the state of a specified light.
+ *
+ * @hide
+ */
+ @Override
+ public @NonNull LightState getLightState(@NonNull Light light) {
+ Preconditions.checkNotNull(light);
+ return mInputManager.getLightState(mDeviceId, light);
+ }
+
+ /**
+ * Creates a new LightsSession that can be used to control the device lights.
+ */
+ @Override
+ public @NonNull LightsSession openSession() {
+ final LightsSession session = new InputDeviceLightsSession();
+ mInputManager.openLightSession(mDeviceId, mPackageName, session.getToken());
+ return session;
+ }
+
+ /**
+ * Encapsulates a session that can be used to control device lights and represents the lifetime
+ * of the requests.
+ */
+ public final class InputDeviceLightsSession extends LightsManager.LightsSession
+ implements AutoCloseable {
+
+ private final CloseGuard mCloseGuard = new CloseGuard();
+ private boolean mClosed = false;
+
+ /**
+ * Instantiated by {@link LightsManager#openSession()}.
+ */
+ private InputDeviceLightsSession() {
+ mCloseGuard.open("close");
+ }
+
+ /**
+ * Sends a request to modify the states of multiple lights.
+ *
+ * @param request the settings for lights that should change
+ */
+ @Override
+ public void requestLights(@NonNull LightsRequest request) {
+ Preconditions.checkNotNull(request);
+ Preconditions.checkArgument(!mClosed);
+
+ mInputManager.requestLights(mDeviceId, request, getToken());
+ }
+
+ /**
+ * Closes the session, reverting all changes made through it.
+ */
+ @Override
+ public void close() {
+ if (!mClosed) {
+ mInputManager.closeLightSession(mDeviceId, getToken());
+ mClosed = true;
+ mCloseGuard.close();
+ }
+ Reference.reachabilityFence(this);
+ }
+
+ /** @hide */
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ mCloseGuard.warnIfOpen();
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+ }
+
+}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 8a01c660ebd0..e15d6298d63d 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -30,6 +30,10 @@ import android.compat.annotation.ChangeId;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.hardware.SensorManager;
+import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
+import android.hardware.lights.LightsManager;
+import android.hardware.lights.LightsRequest;
import android.os.BlockUntrustedTouchesMode;
import android.os.Build;
import android.os.CombinedVibrationEffect;
@@ -1409,7 +1413,7 @@ public final class InputManager {
}
/**
- * Gets a vibrator service associated with an input device, always create a new instance.
+ * Gets a vibrator service associated with an input device, always creates a new instance.
* @return The vibrator, never null.
* @hide
*/
@@ -1418,7 +1422,7 @@ public final class InputManager {
}
/**
- * Gets a vibrator manager service associated with an input device, always create a new
+ * Gets a vibrator manager service associated with an input device, always creates a new
* instance.
* @return The vibrator manager, never null.
* @hide
@@ -1486,10 +1490,8 @@ public final class InputManager {
/**
* Register input device vibrator state listener
- *
- * @hide
*/
- public boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) {
+ boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) {
try {
return mIm.registerVibratorStateListener(deviceId, listener);
} catch (RemoteException ex) {
@@ -1499,10 +1501,8 @@ public final class InputManager {
/**
* Unregister input device vibrator state listener
- *
- * @hide
*/
- public boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) {
+ boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) {
try {
return mIm.unregisterVibratorStateListener(deviceId, listener);
} catch (RemoteException ex) {
@@ -1511,7 +1511,7 @@ public final class InputManager {
}
/**
- * Gets a sensor manager service associated with an input device, always create a new instance.
+ * Gets a sensor manager service associated with an input device, always creates a new instance.
* @return The sensor manager, never null.
* @hide
*/
@@ -1533,6 +1533,86 @@ public final class InputManager {
}
/**
+ * Gets a lights manager associated with an input device, always creates a new instance.
+ * @return The lights manager, never null.
+ * @hide
+ */
+ @NonNull
+ public LightsManager getInputDeviceLightsManager(int deviceId) {
+ return new InputDeviceLightsManager(InputManager.this, deviceId);
+ }
+
+ /**
+ * Gets a list of light objects associated with an input device.
+ * @return The list of lights, never null.
+ */
+ @NonNull List<Light> getLights(int deviceId) {
+ try {
+ return mIm.getLights(deviceId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the state of an input device light.
+ * @return the light state
+ */
+ @NonNull LightState getLightState(int deviceId, @NonNull Light light) {
+ try {
+ return mIm.getLightState(deviceId, light.getId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Request to modify the states of multiple lights.
+ *
+ * @param request the settings for lights that should change
+ */
+ void requestLights(int deviceId, @NonNull LightsRequest request, IBinder token) {
+ try {
+ List<Integer> lightIdList = request.getLights();
+ int[] lightIds = new int[lightIdList.size()];
+ for (int i = 0; i < lightIds.length; i++) {
+ lightIds[i] = lightIdList.get(i);
+ }
+ List<LightState> lightStateList = request.getLightStates();
+ mIm.setLightStates(deviceId, lightIds,
+ lightStateList.toArray(new LightState[lightStateList.size()]),
+ token);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Open light session for input device manager
+ *
+ * @param token The token for the light session
+ */
+ void openLightSession(int deviceId, String opPkg, @NonNull IBinder token) {
+ try {
+ mIm.openLightSession(deviceId, opPkg, token);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Close light session
+ *
+ */
+ void closeLightSession(int deviceId, @NonNull IBinder token) {
+ try {
+ mIm.closeLightSession(deviceId, token);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Listens for changes in input devices.
*/
public interface InputDeviceListener {
diff --git a/core/java/android/hardware/input/OWNERS b/core/java/android/hardware/input/OWNERS
index 25e02e1aa6f3..c390b33fa174 100644
--- a/core/java/android/hardware/input/OWNERS
+++ b/core/java/android/hardware/input/OWNERS
@@ -1,6 +1,3 @@
# Bug component: 136048
include /services/core/java/com/android/server/input/OWNERS
-
-michaelwr@google.com
-svv@google.com
diff --git a/core/java/android/hardware/lights/Light.java b/core/java/android/hardware/lights/Light.java
index da270182052d..7bfff5d3af97 100644
--- a/core/java/android/hardware/lights/Light.java
+++ b/core/java/android/hardware/lights/Light.java
@@ -16,22 +16,56 @@
package android.hardware.lights;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Represents a logical light on the device.
*
- * @hide
*/
-@SystemApi
public final class Light implements Parcelable {
+ // These enum values copy the values from {@link com.android.server.lights.LightsManager}
+ // and the light HAL. Since 0-7 are lights reserved for system use, 8 for microphone light is
+ // defined in {@link android.hardware.lights.LightsManager}, following types are available
+ // through this API.
+ /** Type for lights that indicate microphone usage */
+ public static final int LIGHT_TYPE_MICROPHONE = 8;
+
+ /**
+ * Type for lights that indicate a monochrome color LED light.
+ */
+ public static final int LIGHT_TYPE_INPUT_SINGLE = 9;
+
+ /**
+ * Type for lights that indicate a group of LED lights representing player ID.
+ */
+ public static final int LIGHT_TYPE_INPUT_PLAYER_ID = 10;
+
+ /**
+ * Type for lights that indicate a color LED light.
+ */
+ public static final int LIGHT_TYPE_INPUT_RGB = 11;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"LIGHT_TYPE_"},
+ value = {
+ LIGHT_TYPE_INPUT_PLAYER_ID,
+ LIGHT_TYPE_INPUT_SINGLE,
+ LIGHT_TYPE_INPUT_RGB,
+ })
+ public @interface LightType {}
+
private final int mId;
private final int mOrdinal;
private final int mType;
+ private final String mName;
/**
* Creates a new light with the given data.
@@ -39,15 +73,26 @@ public final class Light implements Parcelable {
* @hide
*/
public Light(int id, int ordinal, int type) {
+ this(id, ordinal, type, "Light");
+ }
+
+ /**
+ * Creates a new light with the given data.
+ *
+ * @hide
+ */
+ public Light(int id, int ordinal, int type, String name) {
mId = id;
mOrdinal = ordinal;
mType = type;
+ mName = name;
}
private Light(@NonNull Parcel in) {
mId = in.readInt();
mOrdinal = in.readInt();
mType = in.readInt();
+ mName = in.readString();
}
/** Implement the Parcelable interface */
@@ -56,6 +101,7 @@ public final class Light implements Parcelable {
dest.writeInt(mId);
dest.writeInt(mOrdinal);
dest.writeInt(mType);
+ dest.writeString(mName);
}
/** Implement the Parcelable interface */
@@ -100,6 +146,14 @@ public final class Light implements Parcelable {
}
/**
+ * Returns the name of the light.
+ */
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ /**
* Returns the ordinal of the light.
*
* <p>This is a sort key that represents the physical order of lights on the device with the
diff --git a/core/java/android/hardware/lights/LightState.java b/core/java/android/hardware/lights/LightState.java
index cd39e6df91a9..650b383eeb0f 100644
--- a/core/java/android/hardware/lights/LightState.java
+++ b/core/java/android/hardware/lights/LightState.java
@@ -32,36 +32,93 @@ import android.os.Parcelable;
* will be converted to only a brightness value and that will be used for the light's single
* channel.
*
- * @hide
*/
-@SystemApi
public final class LightState implements Parcelable {
private final int mColor;
+ private final int mPlayerId;
/**
- * Creates a new LightState with the desired color and intensity.
+ * Creates a new LightState with the desired color and intensity, for a light type
+ * of RBG color or monochrome color.
*
* @param color the desired color and intensity in ARGB format.
+ * @deprecated this has been replaced with {@link android.hardware.lights.LightState#forColor }
+ * @hide
*/
+ @Deprecated
+ @SystemApi
public LightState(@ColorInt int color) {
+ this(color, 0);
+ }
+
+ /**
+ * Creates a new LightState with the desired color and intensity, and the player Id.
+ * Player Id will only be applied on Light type
+ * {@link android.hardware.lights.Light#LIGHT_TYPE_INPUT_PLAYER_ID}
+ *
+ * @param color the desired color and intensity in ARGB format.
+ * @hide
+ */
+ public LightState(@ColorInt int color, int playerId) {
mColor = color;
+ mPlayerId = playerId;
+ }
+
+ /**
+ * Creates a new LightState with the desired color and intensity, for a light type
+ * of RBG color or single monochrome color.
+ *
+ * @param color the desired color and intensity in ARGB format.
+ * @return The LightState object contains the color.
+ */
+ @NonNull
+ public static LightState forColor(@ColorInt int color) {
+ return new LightState(color, 0);
+ }
+
+ /**
+ * Creates a new LightState with the desired player id, for a light of type
+ * {@link android.hardware.lights.Light#LIGHT_TYPE_INPUT_PLAYER_ID}.
+ *
+ * @param playerId the desired player id.
+ * @return The LightState object contains the player id.
+ */
+ @NonNull
+ public static LightState forPlayerId(int playerId) {
+ return new LightState(0, playerId);
}
+ /**
+ * Creates a new LightState from a parcel object.
+ */
private LightState(@NonNull Parcel in) {
mColor = in.readInt();
+ mPlayerId = in.readInt();
}
/**
- * Return the color and intensity associated with this LightState.
- * @return the color and intensity in ARGB format. The A channel is ignored.
+ * Returns the color and intensity associated with this LightState.
+ * @return the color and intensity in ARGB format. The A channel is ignored. return 0 when
+ * calling LightsManager.getLightState with LIGHT_TYPE_INPUT_PLAYER_ID.
*/
public @ColorInt int getColor() {
return mColor;
}
+ /**
+ * Returns the player ID associated with this LightState for Light type
+ * {@link android.hardware.lights.Light#LIGHT_TYPE_INPUT_PLAYER_ID},
+ * or 0 for other types.
+ * @return the player ID.
+ */
+ public int getPlayerId() {
+ return mPlayerId;
+ }
+
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mColor);
+ dest.writeInt(mPlayerId);
}
@Override
@@ -69,6 +126,12 @@ public final class LightState implements Parcelable {
return 0;
}
+ @Override
+ public String toString() {
+ return "LightState{Color=0x" + Integer.toHexString(mColor) + ", PlayerId="
+ + mPlayerId + "}";
+ }
+
public static final @NonNull Parcelable.Creator<LightState> CREATOR =
new Parcelable.Creator<LightState>() {
public LightState createFromParcel(Parcel in) {
diff --git a/core/java/android/hardware/lights/LightsManager.java b/core/java/android/hardware/lights/LightsManager.java
index 33e5fcaf2abb..8fd56db33c4b 100644
--- a/core/java/android/hardware/lights/LightsManager.java
+++ b/core/java/android/hardware/lights/LightsManager.java
@@ -16,43 +16,38 @@
package android.hardware.lights;
-import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
-import android.annotation.TestApi;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.ServiceManager.ServiceNotFoundException;
-import android.util.CloseGuard;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.Reference;
import java.util.List;
/**
* The LightsManager class allows control over device lights.
*
- * @hide
*/
-@SystemApi
@SystemService(Context.LIGHTS_SERVICE)
-public final class LightsManager {
+public abstract class LightsManager {
private static final String TAG = "LightsManager";
+ @NonNull private final Context mContext;
// These enum values copy the values from {@link com.android.server.lights.LightsManager}
// and the light HAL. Since 0-7 are lights reserved for system use, only the microphone light
- // is available through this API.
- /** Type for lights that indicate microphone usage */
+ // and following types are available through this API.
+ /** Type for lights that indicate microphone usage
+ * @deprecated this has been moved to {@link android.hardware.lights.Light }
+ * @hide
+ */
+ @Deprecated
+ @SystemApi
public static final int LIGHT_TYPE_MICROPHONE = 8;
/** @hide */
@@ -63,28 +58,11 @@ public final class LightsManager {
})
public @interface LightType {}
- @NonNull private final Context mContext;
- @NonNull private final ILightsManager mService;
-
/**
- * Creates a LightsManager.
- *
- * @hide
+ * @hide to prevent subclassing from outside of the framework
*/
- public LightsManager(@NonNull Context context) throws ServiceNotFoundException {
- this(context, ILightsManager.Stub.asInterface(
- ServiceManager.getServiceOrThrow(Context.LIGHTS_SERVICE)));
- }
-
- /**
- * Creates a LightsManager with a provided service implementation.
- *
- * @hide
- */
- @VisibleForTesting
- public LightsManager(@NonNull Context context, @NonNull ILightsManager service) {
+ public LightsManager(Context context) {
mContext = Preconditions.checkNotNull(context);
- mService = Preconditions.checkNotNull(service);
}
/**
@@ -92,112 +70,44 @@ public final class LightsManager {
*
* @return A list of available lights
*/
- @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
- public @NonNull List<Light> getLights() {
- try {
- return mService.getLights();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+ public @NonNull abstract List<Light> getLights();
/**
* Returns the state of a specified light.
*
- * @hide
*/
- @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
- @TestApi
- public @NonNull LightState getLightState(@NonNull Light light) {
- Preconditions.checkNotNull(light);
- try {
- return mService.getLightState(light.getId());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+ public abstract @NonNull LightState getLightState(@NonNull Light light);
/**
* Creates a new LightsSession that can be used to control the device lights.
*/
- @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
- public @NonNull LightsSession openSession() {
- try {
- final LightsSession session = new LightsSession();
- mService.openSession(session.mToken);
- return session;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+ public abstract @NonNull LightsSession openSession();
/**
* Encapsulates a session that can be used to control device lights and represents the lifetime
* of the requests.
*/
- public final class LightsSession implements AutoCloseable {
-
+ public abstract static class LightsSession implements AutoCloseable {
private final IBinder mToken = new Binder();
-
- private final CloseGuard mCloseGuard = new CloseGuard();
- private boolean mClosed = false;
-
- /**
- * Instantiated by {@link LightsManager#openSession()}.
- */
- @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
- private LightsSession() {
- mCloseGuard.open("close");
- }
-
/**
* Sends a request to modify the states of multiple lights.
*
- * <p>This method only controls lights that aren't overridden by higher-priority sessions.
- * Additionally, lights not controlled by this session can be controlled by lower-priority
- * sessions.
- *
* @param request the settings for lights that should change
*/
- @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
- public void requestLights(@NonNull LightsRequest request) {
- Preconditions.checkNotNull(request);
- if (!mClosed) {
- try {
- mService.setLightStates(mToken, request.mLightIds, request.mLightStates);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- }
+ public abstract void requestLights(@NonNull LightsRequest request);
- /**
- * Closes the session, reverting all changes made through it.
- */
- @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
@Override
- public void close() {
- if (!mClosed) {
- try {
- mService.closeSession(mToken);
- mClosed = true;
- mCloseGuard.close();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- Reference.reachabilityFence(this);
- }
+ public abstract void close();
- /** @hide */
- @Override
- protected void finalize() throws Throwable {
- try {
- mCloseGuard.warnIfOpen();
- close();
- } finally {
- super.finalize();
- }
+ /**
+ * Get the token of a light session.
+ *
+ * @return Binder token of the light session.
+ * @hide
+ */
+ public @NonNull IBinder getToken() {
+ return mToken;
}
}
+
}
diff --git a/core/java/android/hardware/lights/LightsRequest.java b/core/java/android/hardware/lights/LightsRequest.java
index a318992c35ee..2626a461aaf5 100644
--- a/core/java/android/hardware/lights/LightsRequest.java
+++ b/core/java/android/hardware/lights/LightsRequest.java
@@ -17,17 +17,17 @@
package android.hardware.lights;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.util.SparseArray;
import com.android.internal.util.Preconditions;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
/**
* Encapsulates a request to modify the state of multiple lights.
*
- * @hide
*/
-@SystemApi
public final class LightsRequest {
/** Visible to {@link LightsManager.Session}. */
@@ -50,6 +50,30 @@ public final class LightsRequest {
}
/**
+ * Get a list of Light as ids. The ids will returned in same order as the lights passed
+ * in Builder.
+ *
+ * @return List of light ids
+ */
+ public @NonNull List<Integer> getLights() {
+ List<Integer> lightList = new ArrayList<Integer>(mLightIds.length);
+ for (int i = 0; i < mLightIds.length; i++) {
+ lightList.add(mLightIds[i]);
+ }
+ return lightList;
+ }
+
+ /**
+ * Get a list of LightState. The states will be returned in same order as the light states
+ * passed in Builder.
+ *
+ * @return List of light states
+ */
+ public @NonNull List<LightState> getLightStates() {
+ return Arrays.asList(mLightStates);
+ }
+
+ /**
* Builder for creating device light change requests.
*/
public static final class Builder {
@@ -62,7 +86,7 @@ public final class LightsRequest {
* @param light the light to modify
* @param state the desired color and intensity of the light
*/
- public @NonNull Builder setLight(@NonNull Light light, @NonNull LightState state) {
+ public @NonNull Builder addLight(@NonNull Light light, @NonNull LightState state) {
Preconditions.checkNotNull(light);
Preconditions.checkNotNull(state);
mChanges.put(light.getId(), state);
diff --git a/core/java/android/hardware/lights/SystemLightsManager.java b/core/java/android/hardware/lights/SystemLightsManager.java
new file mode 100644
index 000000000000..726a61359c01
--- /dev/null
+++ b/core/java/android/hardware/lights/SystemLightsManager.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.lights;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.hardware.lights.LightsManager.LightsSession;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.util.CloseGuard;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.lang.ref.Reference;
+import java.util.List;
+
+/**
+ * The LightsManager class allows control over device lights.
+ *
+ * @hide
+ */
+public final class SystemLightsManager extends LightsManager {
+ private static final String TAG = "LightsManager";
+
+ @NonNull private final ILightsManager mService;
+
+ /**
+ * Creates a SystemLightsManager.
+ *
+ * @hide
+ */
+ public SystemLightsManager(@NonNull Context context) throws ServiceNotFoundException {
+ this(context, ILightsManager.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.LIGHTS_SERVICE)));
+ }
+
+ /**
+ * Creates a SystemLightsManager with a provided service implementation.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public SystemLightsManager(@NonNull Context context, @NonNull ILightsManager service) {
+ super(context);
+ mService = Preconditions.checkNotNull(service);
+ }
+
+ /**
+ * Returns the lights available on the device.
+ *
+ * @return A list of available lights
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+ @Override
+ public @NonNull List<Light> getLights() {
+ try {
+ return mService.getLights();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the state of a specified light.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+ @Override
+ public @NonNull LightState getLightState(@NonNull Light light) {
+ Preconditions.checkNotNull(light);
+ try {
+ return mService.getLightState(light.getId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Creates a new LightsSession that can be used to control the device lights.
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+ @Override
+ public @NonNull LightsSession openSession() {
+ try {
+ final LightsSession session = new SystemLightsSession();
+ mService.openSession(session.getToken());
+ return session;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Encapsulates a session that can be used to control device lights and represents the lifetime
+ * of the requests.
+ */
+ public final class SystemLightsSession extends LightsManager.LightsSession
+ implements AutoCloseable {
+
+ private final CloseGuard mCloseGuard = new CloseGuard();
+ private boolean mClosed = false;
+
+ /**
+ * Instantiated by {@link LightsManager#openSession()}.
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+ private SystemLightsSession() {
+ mCloseGuard.open("close");
+ }
+
+ /**
+ * Sends a request to modify the states of multiple lights.
+ *
+ * <p>This method only controls lights that aren't overridden by higher-priority sessions.
+ * Additionally, lights not controlled by this session can be controlled by lower-priority
+ * sessions.
+ *
+ * @param request the settings for lights that should change
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+ @Override
+ public void requestLights(@NonNull LightsRequest request) {
+ Preconditions.checkNotNull(request);
+ if (!mClosed) {
+ try {
+ mService.setLightStates(getToken(), request.mLightIds, request.mLightStates);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Closes the session, reverting all changes made through it.
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+ @Override
+ public void close() {
+ if (!mClosed) {
+ try {
+ mService.closeSession(getToken());
+ mClosed = true;
+ mCloseGuard.close();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ Reference.reachabilityFence(this);
+ }
+
+ /** @hide */
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ mCloseGuard.warnIfOpen();
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+ }
+}
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 5cfcd667632b..9198eb74d1f8 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -171,7 +171,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
SomeArgs args = (SomeArgs) msg.obj;
try {
inputMethod.initializeInternal((IBinder) args.arg1, msg.arg1,
- (IInputMethodPrivilegedOperations) args.arg2);
+ (IInputMethodPrivilegedOperations) args.arg2, (int) args.arg3);
} finally {
args.recycle();
}
@@ -280,9 +280,10 @@ class IInputMethodWrapper extends IInputMethod.Stub
@BinderThread
@Override
public void initializeInternal(IBinder token, int displayId,
- IInputMethodPrivilegedOperations privOps) {
+ IInputMethodPrivilegedOperations privOps, int configChanges) {
mCaller.executeOrSendMessage(
- mCaller.obtainMessageIOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps));
+ mCaller.obtainMessageIOOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps,
+ configChanges));
}
@BinderThread
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7e2be01feb01..03dd3067e64e 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -70,6 +70,7 @@ import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -131,6 +132,7 @@ import android.widget.TextView;
import android.window.WindowMetricsHelper;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
@@ -513,6 +515,8 @@ public class InputMethodService extends AbstractInputMethodService {
private boolean mIsAutomotive;
private Handler mHandler;
private boolean mImeSurfaceScheduledForRemoval;
+ private Configuration mLastKnownConfig;
+ private int mHandledConfigChanges;
/**
* An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput}
@@ -588,12 +592,14 @@ public class InputMethodService extends AbstractInputMethodService {
@MainThread
@Override
public final void initializeInternal(@NonNull IBinder token, int displayId,
- IInputMethodPrivilegedOperations privilegedOperations) {
+ IInputMethodPrivilegedOperations privilegedOperations,
+ int configChanges) {
if (InputMethodPrivilegedOperationsRegistry.isRegistered(token)) {
Log.w(TAG, "The token has already registered, ignore this initialization.");
return;
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
+ mHandledConfigChanges = configChanges;
mPrivOps.set(privilegedOperations);
InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps);
updateInputMethodDisplay(displayId);
@@ -821,6 +827,9 @@ public class InputMethodService extends AbstractInputMethodService {
setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
}
final boolean isVisible = isInputViewShown();
+ if (isVisible && getResources() != null) {
+ mLastKnownConfig = getResources().getConfiguration();
+ }
final boolean visibilityChanged = isVisible != wasVisible;
if (resultReceiver != null) {
resultReceiver.send(visibilityChanged
@@ -1428,10 +1437,37 @@ public class InputMethodService extends AbstractInputMethodService {
* state: {@link #onStartInput} if input is active, and
* {@link #onCreateInputView} and {@link #onStartInputView} and related
* appropriate functions if the UI is displayed.
+ * <p>Starting with {@link Build.VERSION_CODES#S}, IMEs can opt into handling configuration
+ * changes themselves instead of being restarted with
+ * {@link android.R.styleable#InputMethod_configChanges}.
*/
@Override public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- resetStateForNewConfiguration();
+ if (shouldImeRestartForConfig(newConfig)) {
+ resetStateForNewConfiguration();
+ }
+ }
+
+ /**
+ * @return {@code true} if {@link InputMethodService} needs to restart to handle
+ * .{@link #onConfigurationChanged(Configuration)}
+ */
+ @VisibleForTesting
+ boolean shouldImeRestartForConfig(@NonNull Configuration newConfig) {
+ if (mLastKnownConfig == null) {
+ return true;
+ }
+ // If the new config is the same as the config this Service is already running with,
+ // then don't bother calling resetStateForNewConfiguration.
+ int diff = mLastKnownConfig.diffPublicOnly(newConfig);
+ if (diff != 0) {
+ // remove attrs not-relevant to IME service.
+ diff &= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
+ diff &= ActivityInfo.CONFIG_KEYBOARD;
+ diff &= ActivityInfo.CONFIG_NAVIGATION;
+ }
+ int unhandledDiff = (diff & ~mHandledConfigChanges);
+ return unhandledDiff != 0;
}
private void resetStateForNewConfiguration() {
@@ -3181,7 +3217,17 @@ public class InputMethodService extends AbstractInputMethodService {
requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
}
}
-
+
+ @VisibleForTesting
+ void setLastKnownConfig(@NonNull Configuration config) {
+ mLastKnownConfig = config;
+ }
+
+ @VisibleForTesting
+ void setHandledConfigChanges(int configChanges) {
+ mHandledConfigChanges = configChanges;
+ }
+
void startExtractingText(boolean inputChanged) {
final ExtractEditText eet = mExtractEditText;
if (eet != null && getCurrentInputStarted()
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 6353a25e745f..664120698971 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -16,14 +16,17 @@
package android.net;
+import static android.app.ActivityManager.procStateToString;
import static android.content.pm.PackageManager.GET_SIGNATURES;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessCapability;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
@@ -617,8 +620,18 @@ public class NetworkPolicyManager {
* to access network when the device is idle or in battery saver mode. Otherwise, false.
* @hide
*/
- public static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(int procState) {
- return procState <= FOREGROUND_THRESHOLD_STATE;
+ public static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(@Nullable UidState uidState) {
+ if (uidState == null) {
+ return false;
+ }
+ return isProcStateAllowedWhileIdleOrPowerSaveMode(uidState.procState, uidState.capability);
+ }
+
+ /** @hide */
+ public static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(
+ int procState, @ProcessCapability int capability) {
+ return procState <= FOREGROUND_THRESHOLD_STATE
+ || (capability & ActivityManager.PROCESS_CAPABILITY_NETWORK) != 0;
}
/**
@@ -626,11 +639,44 @@ public class NetworkPolicyManager {
* to access network when the device is in data saver mode. Otherwise, false.
* @hide
*/
+ public static boolean isProcStateAllowedWhileOnRestrictBackground(@Nullable UidState uidState) {
+ if (uidState == null) {
+ return false;
+ }
+ return isProcStateAllowedWhileOnRestrictBackground(uidState.procState);
+ }
+
+ /** @hide */
public static boolean isProcStateAllowedWhileOnRestrictBackground(int procState) {
+ // Data saver and bg policy restrictions will only take procstate into account.
return procState <= FOREGROUND_THRESHOLD_STATE;
}
/** @hide */
+ public static final class UidState {
+ public int uid;
+ public int procState;
+ public int capability;
+
+ public UidState(int uid, int procState, int capability) {
+ this.uid = uid;
+ this.procState = procState;
+ this.capability = capability;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("{procState=");
+ sb.append(procStateToString(procState));
+ sb.append(",cap=");
+ ActivityManager.printCapabilitiesSummary(sb, capability);
+ sb.append("}");
+ return sb.toString();
+ }
+ }
+
+ /** @hide */
@TestApi
@NonNull
public static String resolveNetworkId(@NonNull WifiConfiguration config) {
diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java
index 79f9e6ef2a97..dbb312720373 100644
--- a/core/java/android/net/NetworkStack.java
+++ b/core/java/android/net/NetworkStack.java
@@ -15,9 +15,6 @@
*/
package android.net;
-import static android.Manifest.permission.NETWORK_STACK;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -26,8 +23,7 @@ import android.content.Context;
import android.os.IBinder;
import android.os.ServiceManager;
-import java.util.ArrayList;
-import java.util.Arrays;
+import com.android.net.module.util.PermissionUtils;
/**
* Constants and utilities for client code communicating with the network stack service.
* @hide
@@ -79,9 +75,14 @@ public class NetworkStack {
* @param context {@link android.content.Context} for the process.
*
* @hide
+ *
+ * @deprecated Use {@link PermissionUtils#enforceNetworkStackPermission} instead.
+ *
+ * TODO: remove this method and let the users call to PermissionUtils directly.
*/
+ @Deprecated
public static void checkNetworkStackPermission(final @NonNull Context context) {
- checkNetworkStackPermissionOr(context);
+ PermissionUtils.enforceNetworkStackPermission(context);
}
/**
@@ -92,31 +93,14 @@ public class NetworkStack {
* @param otherPermissions The set of permissions that could be the candidate permissions , or
* empty string if none of other permissions needed.
* @hide
+ *
+ * @deprecated Use {@link PermissionUtils#enforceNetworkStackPermissionOr} instead.
+ *
+ * TODO: remove this method and let the users call to PermissionUtils directly.
*/
+ @Deprecated
public static void checkNetworkStackPermissionOr(final @NonNull Context context,
final @NonNull String... otherPermissions) {
- ArrayList<String> permissions = new ArrayList<String>(Arrays.asList(otherPermissions));
- permissions.add(NETWORK_STACK);
- permissions.add(PERMISSION_MAINLINE_NETWORK_STACK);
- enforceAnyPermissionOf(context, permissions.toArray(new String[0]));
+ PermissionUtils.enforceNetworkStackPermissionOr(context, otherPermissions);
}
-
- private static void enforceAnyPermissionOf(final @NonNull Context context,
- final @NonNull String... permissions) {
- if (!checkAnyPermissionOf(context, permissions)) {
- throw new SecurityException("Requires one of the following permissions: "
- + String.join(", ", permissions) + ".");
- }
- }
-
- private static boolean checkAnyPermissionOf(final @NonNull Context context,
- final @NonNull String... permissions) {
- for (String permission : permissions) {
- if (context.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
- return true;
- }
- }
- return false;
- }
-
}
diff --git a/core/java/android/net/NetworkWatchlistManager.java b/core/java/android/net/NetworkWatchlistManager.java
index 49047d3a0c87..8f6510ed3ea5 100644
--- a/core/java/android/net/NetworkWatchlistManager.java
+++ b/core/java/android/net/NetworkWatchlistManager.java
@@ -16,6 +16,8 @@
package android.net;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;
@@ -29,6 +31,7 @@ import com.android.internal.util.Preconditions;
* Class that manage network watchlist in system.
* @hide
*/
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@SystemService(Context.NETWORK_WATCHLIST_SERVICE)
public class NetworkWatchlistManager {
@@ -90,6 +93,7 @@ public class NetworkWatchlistManager {
/**
* Get Network Watchlist config file hash.
*/
+ @Nullable
public byte[] getWatchlistConfigHash() {
try {
return mNetworkWatchlistManager.getWatchlistConfigHash();
diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java
index b172ccc4e370..f0e7da78d669 100644
--- a/core/java/android/net/UidRange.java
+++ b/core/java/android/net/UidRange.java
@@ -42,10 +42,6 @@ public final class UidRange implements Parcelable {
stop = stopUid;
}
- public static UidRange createForUser(int userId) {
- return new UidRange(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
- }
-
/** Creates a UidRange for the specified user. */
public static UidRange createForUser(UserHandle user) {
final UserHandle nextUser = UserHandle.of(user.getIdentifier() + 1);
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index e43b0b6fa635..f90fbaf1e0fb 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -596,7 +596,8 @@ public class VpnService extends Service {
}
}
}
- mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null));
+ mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null, null,
+ RouteInfo.RTN_UNICAST));
mConfig.updateAllowedFamilies(address);
return this;
}
diff --git a/core/java/android/net/vcn/IVcnStatusCallback.aidl b/core/java/android/net/vcn/IVcnStatusCallback.aidl
index 555e9b5883e8..d91cef592d10 100644
--- a/core/java/android/net/vcn/IVcnStatusCallback.aidl
+++ b/core/java/android/net/vcn/IVcnStatusCallback.aidl
@@ -17,8 +17,9 @@
package android.net.vcn;
/** @hide */
-interface IVcnStatusCallback {
+oneway interface IVcnStatusCallback {
void onEnteredSafeMode();
+ void onVcnStatusChanged(int statusCode);
void onGatewayConnectionError(
in int[] gatewayNetworkCapabilities,
int errorCode,
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index aea0ea988f50..eb8c251fec78 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -21,6 +21,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
import android.net.LinkProperties;
@@ -72,8 +73,7 @@ import java.util.concurrent.Executor;
public class VcnManager {
@NonNull private static final String TAG = VcnManager.class.getSimpleName();
- private static final Map<
- VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
+ private static final Map<VcnNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>();
@NonNull private final Context mContext;
@@ -93,13 +93,13 @@ public class VcnManager {
}
/**
- * Get all currently registered VcnUnderlyingNetworkPolicyListeners for testing purposes.
+ * Get all currently registered VcnNetworkPolicyListeners for testing purposes.
*
* @hide
*/
@VisibleForTesting(visibility = Visibility.PRIVATE)
@NonNull
- public static Map<VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
+ public static Map<VcnNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
getAllPolicyListeners() {
return Collections.unmodifiableMap(REGISTERED_POLICY_LISTENERS);
}
@@ -161,45 +161,126 @@ public class VcnManager {
}
}
- // TODO: make VcnUnderlyingNetworkPolicyListener @SystemApi
+ // TODO(b/180537630): remove all VcnUnderlyingNetworkPolicyListener refs once Telephony is using
+ // the new VcnNetworkPolicyListener API
/**
* VcnUnderlyingNetworkPolicyListener is the interface through which internal system components
* can register to receive updates for VCN-underlying Network policies from the System Server.
*
* @hide
*/
- public interface VcnUnderlyingNetworkPolicyListener {
+ public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyListener {}
+
+ /**
+ * Add a listener for VCN-underlying network policy updates.
+ *
+ * @param executor the Executor that will be used for invoking all calls to the specified
+ * Listener
+ * @param listener the VcnUnderlyingNetworkPolicyListener to be added
+ * @throws SecurityException if the caller does not have permission NETWORK_FACTORY
+ * @throws IllegalStateException if the specified VcnUnderlyingNetworkPolicyListener is already
+ * registered
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public void addVcnUnderlyingNetworkPolicyListener(
+ @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) {
+ addVcnNetworkPolicyListener(executor, listener);
+ }
+
+ /**
+ * Remove the specified VcnUnderlyingNetworkPolicyListener from VcnManager.
+ *
+ * <p>If the specified listener is not currently registered, this is a no-op.
+ *
+ * @param listener the VcnUnderlyingNetworkPolicyListener that will be removed
+ * @hide
+ */
+ public void removeVcnUnderlyingNetworkPolicyListener(
+ @NonNull VcnUnderlyingNetworkPolicyListener listener) {
+ removeVcnNetworkPolicyListener(listener);
+ }
+
+ /**
+ * Queries the underlying network policy for a network with the given parameters.
+ *
+ * <p>Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy
+ * may have changed via {@link VcnUnderlyingNetworkPolicyListener#onPolicyChanged()}, a Network
+ * Provider MUST poll for the updated Network policy based on that Network's capabilities and
+ * properties.
+ *
+ * @param networkCapabilities the NetworkCapabilities to be used in determining the Network
+ * policy for this Network.
+ * @param linkProperties the LinkProperties to be used in determining the Network policy for
+ * this Network.
+ * @throws SecurityException if the caller does not have permission NETWORK_FACTORY
+ * @return the VcnUnderlyingNetworkPolicy to be used for this Network.
+ * @hide
+ */
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(
+ @NonNull NetworkCapabilities networkCapabilities,
+ @NonNull LinkProperties linkProperties) {
+ requireNonNull(networkCapabilities, "networkCapabilities must not be null");
+ requireNonNull(linkProperties, "linkProperties must not be null");
+
+ try {
+ return mService.getUnderlyingNetworkPolicy(networkCapabilities, linkProperties);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * VcnNetworkPolicyListener is the interface through which internal system components (e.g.
+ * Network Factories) can register to receive updates for VCN-underlying Network policies from
+ * the System Server.
+ *
+ * <p>Any Network Factory that brings up Networks capable of being VCN-underlying Networks
+ * should register a VcnNetworkPolicyListener. VcnManager will then use this listener to notify
+ * the registrant when VCN Network policies change. Upon receiving this signal, the listener
+ * must check {@link VcnManager} for the current Network policy result for each of its Networks
+ * via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface VcnNetworkPolicyListener {
/**
* Notifies the implementation that the VCN's underlying Network policy has changed.
*
- * <p>After receiving this callback, implementations MUST poll VcnManager for the updated
- * VcnUnderlyingNetworkPolicy via VcnManager#getUnderlyingNetworkPolicy.
+ * <p>After receiving this callback, implementations should get the current {@link
+ * VcnNetworkPolicyResult} via {@link #applyVcnNetworkPolicy(NetworkCapabilities,
+ * LinkProperties)}.
*/
void onPolicyChanged();
}
/**
- * Add a listener for VCN-underlying network policy updates.
+ * Add a listener for VCN-underlying Network policy updates.
+ *
+ * <p>A {@link VcnNetworkPolicyListener} is eligible to begin receiving callbacks once it is
+ * registered. No callbacks are guaranteed upon registration.
*
* @param executor the Executor that will be used for invoking all calls to the specified
* Listener
- * @param listener the VcnUnderlyingNetworkPolicyListener to be added
+ * @param listener the VcnNetworkPolicyListener to be added
* @throws SecurityException if the caller does not have permission NETWORK_FACTORY
- * @throws IllegalArgumentException if the specified VcnUnderlyingNetworkPolicyListener is
- * already registered
+ * @throws IllegalStateException if the specified VcnNetworkPolicyListener is already registered
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public void addVcnUnderlyingNetworkPolicyListener(
- @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) {
+ public void addVcnNetworkPolicyListener(
+ @NonNull Executor executor, @NonNull VcnNetworkPolicyListener listener) {
requireNonNull(executor, "executor must not be null");
requireNonNull(listener, "listener must not be null");
VcnUnderlyingNetworkPolicyListenerBinder binder =
new VcnUnderlyingNetworkPolicyListenerBinder(executor, listener);
if (REGISTERED_POLICY_LISTENERS.putIfAbsent(listener, binder) != null) {
- throw new IllegalArgumentException(
- "Attempting to add a listener that is already in use");
+ throw new IllegalStateException("listener is already registered with VcnManager");
}
try {
@@ -211,15 +292,15 @@ public class VcnManager {
}
/**
- * Remove the specified VcnUnderlyingNetworkPolicyListener from VcnManager.
+ * Remove the specified VcnNetworkPolicyListener from VcnManager.
*
* <p>If the specified listener is not currently registered, this is a no-op.
*
- * @param listener the VcnUnderlyingNetworkPolicyListener that will be removed
+ * @param listener the VcnNetworkPolicyListener that will be removed
* @hide
*/
- public void removeVcnUnderlyingNetworkPolicyListener(
- @NonNull VcnUnderlyingNetworkPolicyListener listener) {
+ @SystemApi
+ public void removeVcnNetworkPolicyListener(@NonNull VcnNetworkPolicyListener listener) {
requireNonNull(listener, "listener must not be null");
VcnUnderlyingNetworkPolicyListenerBinder binder =
@@ -236,39 +317,88 @@ public class VcnManager {
}
/**
- * Queries the underlying network policy for a network with the given parameters.
+ * Applies the network policy for a {@link android.net.Network} with the given parameters.
*
* <p>Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy
- * may have changed via {@link VcnUnderlyingNetworkPolicyListener#onPolicyChanged()}, a Network
- * Provider MUST poll for the updated Network policy based on that Network's capabilities and
- * properties.
+ * may have changed via {@link VcnNetworkPolicyListener#onPolicyChanged()}, a Network Provider
+ * MUST poll for the updated Network policy based on that Network's capabilities and properties.
*
* @param networkCapabilities the NetworkCapabilities to be used in determining the Network
- * policy for this Network.
- * @param linkProperties the LinkProperties to be used in determining the Network policy for
- * this Network.
+ * policy result for this Network.
+ * @param linkProperties the LinkProperties to be used in determining the Network policy result
+ * for this Network.
* @throws SecurityException if the caller does not have permission NETWORK_FACTORY
- * @return the VcnUnderlyingNetworkPolicy to be used for this Network.
+ * @return the {@link VcnNetworkPolicyResult} to be used for this Network.
* @hide
*/
@NonNull
+ @SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(
+ public VcnNetworkPolicyResult applyVcnNetworkPolicy(
@NonNull NetworkCapabilities networkCapabilities,
@NonNull LinkProperties linkProperties) {
requireNonNull(networkCapabilities, "networkCapabilities must not be null");
requireNonNull(linkProperties, "linkProperties must not be null");
- try {
- return mService.getUnderlyingNetworkPolicy(networkCapabilities, linkProperties);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ final VcnUnderlyingNetworkPolicy policy =
+ getUnderlyingNetworkPolicy(networkCapabilities, linkProperties);
+ return new VcnNetworkPolicyResult(
+ policy.isTeardownRequested(), policy.getMergedNetworkCapabilities());
}
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef({
+ VCN_STATUS_CODE_NOT_CONFIGURED,
+ VCN_STATUS_CODE_INACTIVE,
+ VCN_STATUS_CODE_ACTIVE,
+ VCN_STATUS_CODE_SAFE_MODE
+ })
+ public @interface VcnStatusCode {}
+
+ /**
+ * Value indicating that the VCN for the subscription group is not configured, or that the
+ * callback is not privileged for the subscription group.
+ *
+ * @hide
+ */
+ public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0;
+
+ /**
+ * Value indicating that the VCN for the subscription group is inactive.
+ *
+ * <p>A VCN is inactive if a {@link VcnConfig} is present for the subscription group, but the
+ * provisioning package is not privileged.
+ *
+ * @hide
+ */
+ public static final int VCN_STATUS_CODE_INACTIVE = 1;
+
+ /**
+ * Value indicating that the VCN for the subscription group is active.
+ *
+ * <p>A VCN is active if a {@link VcnConfig} is present for the subscription, the provisioning
+ * package is privileged, and the VCN is not in Safe Mode. In other words, a VCN is considered
+ * active while it is connecting, fully connected, and disconnecting.
+ *
+ * @hide
+ */
+ public static final int VCN_STATUS_CODE_ACTIVE = 2;
+
+ /**
+ * Value indicating that the VCN for the subscription group is in Safe Mode.
+ *
+ * <p>A VCN will be put into Safe Mode if any of the gateway connections were unable to
+ * establish a connection within a system-determined timeout (while underlying networks were
+ * available).
+ *
+ * @hide
+ */
+ public static final int VCN_STATUS_CODE_SAFE_MODE = 3;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
VCN_ERROR_CODE_INTERNAL_ERROR,
VCN_ERROR_CODE_CONFIG_ERROR,
VCN_ERROR_CODE_NETWORK_ERROR
@@ -323,8 +453,18 @@ public class VcnManager {
*
* <p>A VCN-configuring app may opt to exit safe mode by (re)setting the VCN configuration
* via {@link #setVcnConfig(ParcelUuid, VcnConfig)}.
+ *
+ * @hide
*/
- public abstract void onEnteredSafeMode();
+ public void onEnteredSafeMode() {}
+
+ /**
+ * Invoked when status of the VCN for this callback's subscription group changes.
+ *
+ * @param statusCode the code for the status change encountered by this {@link
+ * VcnStatusCallback}'s subscription group.
+ */
+ public abstract void onVcnStatusChanged(@VcnStatusCode int statusCode);
/**
* Invoked when a VCN Gateway Connection corresponding to this callback's subscription
@@ -356,6 +496,11 @@ public class VcnManager {
* <p>A {@link VcnStatusCallback} will only be invoked if the registering package has carrier
* privileges for the specified subscription at the time of invocation.
*
+ * <p>{@link VcnStatusCallback#onVcnStatusChanged(int)} will be invoked on registration with the
+ * current status for the specified subscription group's VCN. If the registrant is not
+ * privileged for this subscription group, {@link #VCN_STATUS_CODE_NOT_CONFIGURED} will be
+ * returned.
+ *
* @param subscriptionGroup The subscription group to match for callbacks
* @param executor The {@link Executor} to be used for invoking callbacks
* @param callback The VcnStatusCallback to be registered
@@ -415,18 +560,17 @@ public class VcnManager {
}
/**
- * Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System
- * Server.
+ * Binder wrapper for added VcnNetworkPolicyListeners to receive signals from System Server.
*
* @hide
*/
private static class VcnUnderlyingNetworkPolicyListenerBinder
extends IVcnUnderlyingNetworkPolicyListener.Stub {
@NonNull private final Executor mExecutor;
- @NonNull private final VcnUnderlyingNetworkPolicyListener mListener;
+ @NonNull private final VcnNetworkPolicyListener mListener;
private VcnUnderlyingNetworkPolicyListenerBinder(
- Executor executor, VcnUnderlyingNetworkPolicyListener listener) {
+ Executor executor, VcnNetworkPolicyListener listener) {
mExecutor = executor;
mListener = listener;
}
@@ -460,6 +604,12 @@ public class VcnManager {
() -> mExecutor.execute(() -> mCallback.onEnteredSafeMode()));
}
+ @Override
+ public void onVcnStatusChanged(@VcnStatusCode int statusCode) {
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> mCallback.onVcnStatusChanged(statusCode)));
+ }
+
// TODO(b/180521637): use ServiceSpecificException for safer Exception 'parceling'
@Override
public void onGatewayConnectionError(
diff --git a/core/java/android/net/vcn/VcnNetworkPolicyResult.aidl b/core/java/android/net/vcn/VcnNetworkPolicyResult.aidl
new file mode 100644
index 000000000000..3f13abe869da
--- /dev/null
+++ b/core/java/android/net/vcn/VcnNetworkPolicyResult.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn;
+
+/** @hide */
+parcelable VcnNetworkPolicyResult;
diff --git a/core/java/android/net/vcn/VcnNetworkPolicyResult.java b/core/java/android/net/vcn/VcnNetworkPolicyResult.java
new file mode 100644
index 000000000000..5e938200639c
--- /dev/null
+++ b/core/java/android/net/vcn/VcnNetworkPolicyResult.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.net.NetworkCapabilities;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * VcnNetworkPolicyResult represents the Network policy result for a Network transport applying its
+ * VCN policy via {@link VcnManager#applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}.
+ *
+ * <p>Bearers that are bringing up networks capable of acting as a VCN's underlying network should
+ * query for Network policy results upon any capability changes (e.g. changing of TRUSTED bit), and
+ * when prompted by VcnManagementService via {@link VcnManager.VcnNetworkPolicyListener}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class VcnNetworkPolicyResult implements Parcelable {
+ private final boolean mIsTearDownRequested;
+ private final NetworkCapabilities mNetworkCapabilities;
+
+ /**
+ * Constructs a VcnNetworkPolicyResult with the specified parameters.
+ *
+ * @hide
+ */
+ public VcnNetworkPolicyResult(
+ boolean isTearDownRequested, @NonNull NetworkCapabilities networkCapabilities) {
+ Objects.requireNonNull(networkCapabilities, "networkCapabilities must be non-null");
+
+ mIsTearDownRequested = isTearDownRequested;
+ mNetworkCapabilities = networkCapabilities;
+ }
+
+ /**
+ * Returns whether this VCN policy result requires that the underlying Network should be torn
+ * down.
+ *
+ * <p>Upon querying for the current Network policy result, the bearer must check this method,
+ * and MUST tear down the corresponding Network if it returns true.
+ */
+ public boolean isTeardownRequested() {
+ return mIsTearDownRequested;
+ }
+
+ /**
+ * Returns the NetworkCapabilities that the bearer should be using for the corresponding
+ * Network.
+ */
+ @NonNull
+ public NetworkCapabilities getNetworkCapabilities() {
+ return mNetworkCapabilities;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mIsTearDownRequested, mNetworkCapabilities);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof VcnNetworkPolicyResult)) return false;
+ final VcnNetworkPolicyResult that = (VcnNetworkPolicyResult) o;
+
+ return mIsTearDownRequested == that.mIsTearDownRequested
+ && mNetworkCapabilities.equals(that.mNetworkCapabilities);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeBoolean(mIsTearDownRequested);
+ dest.writeParcelable(mNetworkCapabilities, flags);
+ }
+
+ /** Implement the Parcelable interface */
+ public static final @NonNull Creator<VcnNetworkPolicyResult> CREATOR =
+ new Creator<VcnNetworkPolicyResult>() {
+ public VcnNetworkPolicyResult createFromParcel(Parcel in) {
+ return new VcnNetworkPolicyResult(in.readBoolean(), in.readParcelable(null));
+ }
+
+ public VcnNetworkPolicyResult[] newArray(int size) {
+ return new VcnNetworkPolicyResult[size];
+ }
+ };
+}
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
index dd7c86d87ff2..b47d5642419e 100644
--- a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
@@ -33,8 +33,7 @@ import java.util.Objects;
* @hide
*/
public final class VcnUnderlyingNetworkPolicy implements Parcelable {
- private final boolean mIsTearDownRequested;
- private final NetworkCapabilities mMergedNetworkCapabilities;
+ private final VcnNetworkPolicyResult mVcnNetworkPolicyResult;
/**
* Constructs a VcnUnderlyingNetworkPolicy with the specified parameters.
@@ -46,8 +45,13 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable {
Objects.requireNonNull(
mergedNetworkCapabilities, "mergedNetworkCapabilities must be nonnull");
- mIsTearDownRequested = isTearDownRequested;
- mMergedNetworkCapabilities = mergedNetworkCapabilities;
+ mVcnNetworkPolicyResult =
+ new VcnNetworkPolicyResult(isTearDownRequested, mergedNetworkCapabilities);
+ }
+
+ private VcnUnderlyingNetworkPolicy(@NonNull VcnNetworkPolicyResult vcnNetworkPolicyResult) {
+ this.mVcnNetworkPolicyResult =
+ Objects.requireNonNull(vcnNetworkPolicyResult, "vcnNetworkPolicyResult");
}
/**
@@ -55,7 +59,7 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable {
* be torn down.
*/
public boolean isTeardownRequested() {
- return mIsTearDownRequested;
+ return mVcnNetworkPolicyResult.isTeardownRequested();
}
/**
@@ -64,12 +68,12 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable {
*/
@NonNull
public NetworkCapabilities getMergedNetworkCapabilities() {
- return mMergedNetworkCapabilities;
+ return mVcnNetworkPolicyResult.getNetworkCapabilities();
}
@Override
public int hashCode() {
- return Objects.hash(mIsTearDownRequested, mMergedNetworkCapabilities);
+ return Objects.hash(mVcnNetworkPolicyResult);
}
@Override
@@ -78,8 +82,7 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable {
if (!(o instanceof VcnUnderlyingNetworkPolicy)) return false;
final VcnUnderlyingNetworkPolicy that = (VcnUnderlyingNetworkPolicy) o;
- return mIsTearDownRequested == that.mIsTearDownRequested
- && mMergedNetworkCapabilities.equals(that.mMergedNetworkCapabilities);
+ return mVcnNetworkPolicyResult.equals(that.mVcnNetworkPolicyResult);
}
/** {@inheritDoc} */
@@ -91,16 +94,14 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable {
/** {@inheritDoc} */
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeBoolean(mIsTearDownRequested);
- dest.writeParcelable(mMergedNetworkCapabilities, flags);
+ dest.writeParcelable(mVcnNetworkPolicyResult, flags);
}
/** Implement the Parcelable interface */
public static final @NonNull Creator<VcnUnderlyingNetworkPolicy> CREATOR =
new Creator<VcnUnderlyingNetworkPolicy>() {
public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) {
- return new VcnUnderlyingNetworkPolicy(
- in.readBoolean(), in.readParcelable(null));
+ return new VcnUnderlyingNetworkPolicy(in.readParcelable(null));
}
public VcnUnderlyingNetworkPolicy[] newArray(int size) {
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 305c686f8657..a435ac12d33c 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -25,6 +25,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SuppressAutoDoc;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.WorkerThread;
import android.app.ActivityManager;
import android.content.Context;
import android.util.Log;
@@ -41,7 +42,15 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.Executor;
-/** Class that provides a privileged API to capture and consume bugreports. */
+/**
+ * Class that provides a privileged API to capture and consume bugreports.
+ *
+ * <p>This class may only be used by apps that currently have carrier privileges (see {@link
+ * android.telephony.TelephonyManager#hasCarrierPrivileges}) on an active SIM or priv-apps
+ * explicitly allowed by the device manufacturer.
+ *
+ * <p>Only one bugreport can be generated by the system at a time.
+ */
@SystemService(Context.BUGREPORT_SERVICE)
public final class BugreportManager {
@@ -56,7 +65,12 @@ public final class BugreportManager {
mBinder = binder;
}
- /** An interface describing the callback for bugreport progress and status. */
+ /**
+ * An interface describing the callback for bugreport progress and status.
+ *
+ * <p>In general, callers can expect to receive {@link #onProgress} calls as the bugreport
+ * progresses, followed by a terminal call to either {@link #onFinished} or {@link #onError}.
+ */
public abstract static class BugreportCallback {
/**
* Possible error codes taking a bugreport can encounter.
@@ -75,15 +89,18 @@ public final class BugreportManager {
})
public @interface BugreportErrorCode {}
- /** The input options were invalid */
+ /**
+ * The input options were invalid. For example, the destination file the app provided could
+ * not be written by the system.
+ */
public static final int BUGREPORT_ERROR_INVALID_INPUT =
IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT;
- /** A runtime error occurred */
+ /** A runtime error occurred. */
public static final int BUGREPORT_ERROR_RUNTIME =
IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR;
- /** User denied consent to share the bugreport */
+ /** User denied consent to share the bugreport. */
public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT =
IDumpstateListener.BUGREPORT_ERROR_USER_DENIED_CONSENT;
@@ -149,6 +166,7 @@ public final class BugreportManager {
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.DUMP)
+ @WorkerThread
public void startBugreport(
@NonNull ParcelFileDescriptor bugreportFd,
@Nullable ParcelFileDescriptor screenshotFd,
@@ -222,6 +240,7 @@ public final class BugreportManager {
* @param callback callback for progress and status updates.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @WorkerThread
public void startConnectivityBugreport(
@NonNull ParcelFileDescriptor bugreportFd,
@NonNull @CallbackExecutor Executor executor,
@@ -247,6 +266,7 @@ public final class BugreportManager {
* @throws SecurityException if trying to cancel another app's bugreport in progress
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @WorkerThread
public void cancelBugreport() {
try {
mBinder.cancelBugreport(-1 /* callingUid */, mContext.getOpPackageName());
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 93c1690e3813..43184ea4b9a9 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -26,6 +26,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
@@ -631,10 +632,15 @@ public class RecoverySystem {
/**
* Prepare to apply an unattended update by asking the user for their Lock Screen Knowledge
* Factor (LSKF). If supplied, the {@code intentSender} will be called when the system is setup
- * and ready to apply the OTA. This API is expected to handle requests from multiple clients
- * simultaneously, e.g. from ota and mainline.
+ * and ready to apply the OTA. <p>
*
- * <p> The behavior of multi-client Resume on Reboot works as follows
+ * <p> If the device doesn't setup a lock screen, i.e. by checking
+ * {@link KeyguardManager#isKeyguardSecure()}, this API call will fail and throw an exception.
+ * Callers are expected to use {@link PowerManager#reboot(String)} directly without going
+ * through the RoR flow. <p>
+ *
+ * <p> This API is expected to handle requests from multiple clients simultaneously, e.g.
+ * from ota and mainline. The behavior of multi-client Resume on Reboot works as follows
* <li> Each client should call this function to prepare for Resume on Reboot before calling
* {@link #rebootAndApply(Context, String, boolean)} </li>
* <li> One client cannot clear the Resume on Reboot preparation of another client. </li>
@@ -658,6 +664,13 @@ public class RecoverySystem {
if (updateToken == null) {
throw new NullPointerException("updateToken == null");
}
+
+ KeyguardManager keyguardManager = context.getSystemService(KeyguardManager.class);
+ if (keyguardManager == null || !keyguardManager.isDeviceSecure()) {
+ throw new IOException("Failed to request LSKF because the device doesn't have a"
+ + " lock screen. ");
+ }
+
RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
if (!rs.requestLskf(context.getPackageName(), intentSender)) {
throw new IOException("preparation for update failed");
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index d6fa733927fb..b003d238c268 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -186,7 +186,8 @@ public abstract class Vibrator {
/**
* Return the ID of this vibrator.
*
- * @return The id of the vibrator controlled by this service.
+ * @return A non-negative integer representing the id of the vibrator controlled by this
+ * service, or -1 this service is not attached to any physical vibrator.
*/
public int getId() {
return -1;
diff --git a/core/java/android/os/VibratorManager.java b/core/java/android/os/VibratorManager.java
index 5dd38b6cbd86..5a01814508e1 100644
--- a/core/java/android/os/VibratorManager.java
+++ b/core/java/android/os/VibratorManager.java
@@ -91,10 +91,10 @@ public abstract class VibratorManager {
*
* <p>
* Pass in a {@link CombinedVibrationEffect} representing a combination of {@link
- * VibrationEffect} to be played on one or more vibrators.
+ * VibrationEffect VibrationEffects} to be played on one or more vibrators.
* </p>
*
- * @param effect an array of longs of times for which to turn the vibrator on or off.
+ * @param effect a combination of effects to be performed by one or more vibrators.
*/
@RequiresPermission(android.Manifest.permission.VIBRATE)
public final void vibrate(@NonNull CombinedVibrationEffect effect) {
@@ -109,7 +109,7 @@ public abstract class VibratorManager {
* VibrationEffect} to be played on one or more vibrators.
* </p>
*
- * @param effect an array of longs of times for which to turn the vibrator on or off.
+ * @param effect a combination of effects to be performed by one or more vibrators.
* @param attributes {@link VibrationAttributes} corresponding to the vibration. For example,
* specify {@link VibrationAttributes#USAGE_ALARM} for alarm vibrations or
* {@link VibrationAttributes#USAGE_RINGTONE} for vibrations associated with
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index a078e0434867..73520e07d118 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -59,7 +59,6 @@ public final class IncrementalFileStorages {
/**
* Set up files and directories used in an installation session. Only used by Incremental.
* All the files will be created in defaultStorage.
- * TODO(b/133435829): code clean up
*
* @throws IllegalStateException the session is not an Incremental installation session.
* @throws IOException if fails to setup files or directories.
@@ -73,12 +72,10 @@ public final class IncrementalFileStorages {
@Nullable IStorageHealthListener healthListener,
@NonNull List<InstallationFileParcel> addedFiles,
@NonNull PerUidReadTimeouts[] perUidReadTimeouts,
- IPackageLoadingProgressCallback progressCallback) throws IOException {
- // TODO(b/136132412): validity check if session should not be incremental
+ @Nullable IPackageLoadingProgressCallback progressCallback) throws IOException {
IncrementalManager incrementalManager = (IncrementalManager) context.getSystemService(
Context.INCREMENTAL_SERVICE);
if (incrementalManager == null) {
- // TODO(b/146080380): add incremental-specific error code
throw new IOException("Failed to obtain incrementalManager.");
}
@@ -89,7 +86,6 @@ public final class IncrementalFileStorages {
try {
result.addApkFile(file);
} catch (IOException e) {
- // TODO(b/146080380): add incremental-specific error code
throw new IOException(
"Failed to add file to IncFS: " + file.name + ", reason: ", e);
}
@@ -203,7 +199,6 @@ public final class IncrementalFileStorages {
/**
* Resets the states and unbinds storage instances for an installation session.
- * TODO(b/136132412): make sure unnecessary binds are removed but useful storages are kept
*/
public void cleanUp() {
if (mDefaultStorage == null) {
@@ -211,8 +206,8 @@ public final class IncrementalFileStorages {
}
try {
+ mIncrementalManager.unregisterLoadingProgressCallbacks(mStageDir.getAbsolutePath());
mDefaultStorage.unBind(mStageDir.getAbsolutePath());
- mDefaultStorage.unregisterLoadingProgressListener();
} catch (IOException ignored) {
}
mDefaultStorage = null;
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index 05899947c3df..592e98abae63 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -241,10 +241,12 @@ public final class IncrementalManager {
}
/**
- * Checks if device supports V2 calls (e.g. PerUid).
+ * 0 - IncFs is disabled.
+ * 1 - IncFs v1, core features, no PerUid support. Optional in R.
+ * 2 - IncFs v2, PerUid support, fs-verity support. Required in S.
*/
- public static boolean isV2Available() {
- return nativeIsV2Available();
+ public static int getVersion() {
+ return nativeIsEnabled() ? nativeIsV2Available() ? 2 : 1 : 0;
}
/**
@@ -342,7 +344,6 @@ public final class IncrementalManager {
storage.unregisterLoadingProgressListener();
}
- // TODO(b/165841827): handle reboot and app update
public boolean registerCallback(@NonNull IncrementalStorage storage,
@NonNull IPackageLoadingProgressCallback callback) {
final int storageId = storage.getId();
@@ -364,30 +365,6 @@ public final class IncrementalManager {
return storage.registerLoadingProgressListener(this);
}
- public boolean unregisterCallback(@NonNull IncrementalStorage storage,
- @NonNull IPackageLoadingProgressCallback callback) {
- final int storageId = storage.getId();
- final RemoteCallbackList<IPackageLoadingProgressCallback> callbacksForStorage;
- synchronized (mCallbacks) {
- callbacksForStorage = mCallbacks.get(storageId);
- if (callbacksForStorage == null) {
- // no callback has ever been registered on this storage
- return false;
- }
- if (!callbacksForStorage.unregister(callback)) {
- // the callback was not registered
- return false;
- }
- if (callbacksForStorage.getRegisteredCallbackCount() > 0) {
- // other callbacks are still listening on this storage
- return true;
- }
- mCallbacks.delete(storageId);
- }
- // stop listening for this storage
- return storage.unregisterLoadingProgressListener();
- }
-
@Override
public void onStorageLoadingProgressChanged(int storageId, float progress) {
final RemoteCallbackList<IPackageLoadingProgressCallback> callbacksForStorage;
diff --git a/core/java/android/os/strictmode/IncorrectContextUseViolation.java b/core/java/android/os/strictmode/IncorrectContextUseViolation.java
index 11d26cab14b3..d8c22fd94ce9 100644
--- a/core/java/android/os/strictmode/IncorrectContextUseViolation.java
+++ b/core/java/android/os/strictmode/IncorrectContextUseViolation.java
@@ -24,7 +24,7 @@ import android.content.Context;
* instance.
*
* @see Context#getSystemService(String)
- * @see Context#isUiContext(Context)
+ * @see Context#isUiContext
* @see android.os.StrictMode.VmPolicy.Builder#detectIncorrectContextUse()
*/
public final class IncorrectContextUseViolation extends Violation {
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index e134c29520b2..4354920c83ec 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -275,6 +275,14 @@ public final class DeviceConfig {
public static final String NAMESPACE_PROFCOLLECT_NATIVE_BOOT = "profcollect_native_boot";
/**
+ * Namespace for features related to Reboot Readiness detection.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_REBOOT_READINESS = "reboot_readiness";
+
+ /**
* Namespace for Rollback flags that are applied immediately.
*
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6ee7eb25eb2f..345cc84e8593 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -417,6 +417,22 @@ public final class Settings {
"android.settings.MANAGE_UNKNOWN_APP_SOURCES";
/**
+ * Activity Action: Show settings to allow configuration of
+ * {@link Manifest.permission#SCHEDULE_EXACT_ALARM} permission
+ *
+ * Input: Optionally, the Intent's data URI can specify the application package name to
+ * directly invoke the management GUI specific to the package name. For example
+ * "package:com.my.app".
+ * <p>
+ * Output: When a package data uri is passed as input, the activity result is set to
+ * {@link android.app.Activity#RESULT_OK} if the permission was granted to the app. Otherwise,
+ * the result is set to {@link android.app.Activity#RESULT_CANCELED}.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_REQUEST_SCHEDULE_EXACT_ALARM =
+ "android.settings.REQUEST_SCHEDULE_EXACT_ALARM";
+
+ /**
* Activity Action: Show settings to allow configuration of cross-profile access for apps
*
* Input: Optionally, the Intent's data URI can specify the application package name to
@@ -10697,14 +10713,6 @@ public final class Settings {
"hdmi_cec_switch_enabled";
/**
- * HDMI CEC version to use. Defaults to v1.4b.
- * @hide
- */
- @Readable
- public static final String HDMI_CEC_VERSION =
- "hdmi_cec_version";
-
- /**
* Whether TV will automatically turn on upon reception of the CEC command
* &lt;Text View On&gt; or &lt;Image View On&gt;. (0 = false, 1 = true)
*
@@ -14614,29 +14622,6 @@ public final class Settings {
public static final String POWER_BUTTON_VERY_LONG_PRESS =
"power_button_very_long_press";
-
- /**
- * Keyguard should be on the left hand side of the screen, for wide screen layouts.
- *
- * @hide
- */
- public static final int ONE_HANDED_KEYGUARD_SIDE_LEFT = 0;
-
- /**
- * Keyguard should be on the right hand side of the screen, for wide screen layouts.
- *
- * @hide
- */
- public static final int ONE_HANDED_KEYGUARD_SIDE_RIGHT = 1;
- /**
- * In one handed mode, which side the keyguard should be on. Allowable values are one of
- * the ONE_HANDED_KEYGUARD_SIDE_* constants.
- *
- * @hide
- */
- @Readable
- public static final String ONE_HANDED_KEYGUARD_SIDE = "one_handed_keyguard_side";
-
/**
* Keys we no longer back up under the current schema, but want to continue to
* process when restoring historical backup datasets.
diff --git a/core/java/android/provider/SimPhonebookContract.java b/core/java/android/provider/SimPhonebookContract.java
index 074d5f167ec3..030b86339822 100644
--- a/core/java/android/provider/SimPhonebookContract.java
+++ b/core/java/android/provider/SimPhonebookContract.java
@@ -44,8 +44,11 @@ import java.util.Objects;
* The contract between the provider of contact records on the device's SIM cards and applications.
* Contains definitions of the supported URIs and columns.
*
- * <p>This content provider does not support any of the QUERY_ARG_SQL* bundle arguments. An
- * IllegalArgumentException will be thrown if these are included.
+ * <h3>Permissions</h3>
+ * <p>
+ * Querying this provider requires {@link android.Manifest.permission#READ_CONTACTS} and writing
+ * to this provider requires {@link android.Manifest.permission#WRITE_CONTACTS}
+ * </p>
*/
public final class SimPhonebookContract {
@@ -85,7 +88,73 @@ public final class SimPhonebookContract {
}
}
- /** Constants for the contact records on a SIM card. */
+ /**
+ * Constants for the contact records on a SIM card.
+ *
+ * <h3 id="simrecords-data">Data</h3>
+ * <p>
+ * Data is stored in a specific elementary file on a specific SIM card and these are isolated
+ * from each other. SIM cards are identified by their subscription ID. SIM cards may not support
+ * all or even any of the elementary file types. A SIM will have constraints on
+ * the values of the data that can be stored in each elementary file. The available SIMs,
+ * their supported elementary file types and the constraints on the data can be discovered by
+ * querying {@link ElementaryFiles#CONTENT_URI}. Each elementary file has a fixed capacity
+ * for the number of records that may be stored. This can be determined from the value
+ * of the {@link ElementaryFiles#MAX_RECORDS} column.
+ * </p>
+ * <p>
+ * The {@link SimRecords#PHONE_NUMBER} column can only contain dialable characters and this
+ * applies regardless of the SIM that is being used. See
+ * {@link android.telephony.PhoneNumberUtils#isDialable(char)} for more details. Additionally
+ * the phone number can contain at most {@link ElementaryFiles#PHONE_NUMBER_MAX_LENGTH}
+ * characters. The {@link SimRecords#NAME} column can contain at most
+ * {@link ElementaryFiles#NAME_MAX_LENGTH} bytes when it is encoded for storage on the SIM.
+ * Encoding is done internally and so the name should be provided unencoded but the number of
+ * bytes required to encode it will vary depending on the characters it contains. This length
+ * can be determined by calling
+ * {@link SimRecords#getEncodedNameLength(ContentResolver, String)}.
+ * </p>
+ * <h3>Operations </h3>
+ * <dl>
+ * <dd><b>Insert</b></dd>
+ * <p>
+ * Only {@link ElementaryFiles#EF_ADN} supports inserts. {@link SimRecords#PHONE_NUMBER}
+ * is a required column. If the value provided for this column is missing, null, empty
+ * or violates the requirements discussed in the <a href="#simrecords-data">Data</a>
+ * section above an {@link IllegalArgumentException} will be thrown. The
+ * {@link SimRecords#NAME} column may be omitted but if provided and it violates any of
+ * the requirements discussed in the <a href="#simrecords-data">Data</a> section above
+ * an {@link IllegalArgumentException} will be thrown.
+ * </p>
+ * <p>
+ * If an insert is not possible because the elementary file is full then an
+ * {@link IllegalStateException} will be thrown.
+ * </p>
+ * <dd><b>Update</b></dd>
+ * <p>
+ * Updates can only be performed for individual records on {@link ElementaryFiles#EF_ADN}.
+ * A specific record is referenced via the Uri returned by
+ * {@link SimRecords#getItemUri(int, int, int)}. Updates have the same constraints and
+ * behavior for the {@link SimRecords#PHONE_NUMBER} and {@link SimRecords#NAME} as insert.
+ * However, in the case of update the {@link SimRecords#PHONE_NUMBER} may be omitted as
+ * the existing record will already have a valid value.
+ * </p>
+ * <dd><b>Delete</b></dd>
+ * <p>
+ * Delete may only be performed for individual records on {@link ElementaryFiles#EF_ADN}.
+ * Deleting records will free up space for use by future inserts.
+ * </p>
+ * <dd><b>Query</b></dd>
+ * <p>
+ * All the records stored on a specific elementary file can be read via a Uri returned by
+ * {@link SimRecords#getContentUri(int, int)}. This query always returns all records; there
+ * is no support for filtering via a selection. An individual record can be queried via a Uri
+ * returned by {@link SimRecords#getItemUri(int, int, int)}. Queries will throw an
+ * {@link IllegalArgumentException} when the SIM with the subscription ID or the elementary file
+ * type are invalid or unavailable.
+ * </p>
+ * </dl>
+ */
public static final class SimRecords {
/**
@@ -197,8 +266,8 @@ public final class SimPhonebookContract {
* be discovered by querying {@link ElementaryFiles#CONTENT_URI}.
*
* <p>If a SIM with the provided subscription ID does not exist or the SIM with the provided
- * subscription ID doesn't support the specified entity file then queries will return
- * and empty cursor and inserts will throw an {@link IllegalArgumentException}
+ * subscription ID doesn't support the specified entity file then all operations will
+ * throw an {@link IllegalArgumentException}.
*
* @param subscriptionId the subscriptionId of the SIM card that this Uri will reference
* @param efType the elementary file on the SIM that this Uri will reference
@@ -233,6 +302,9 @@ public final class SimPhonebookContract {
* must be greater than 0. If there is no record with this record
* number in the specified entity file then it will be treated as a
* non-existent record.
+ * @see ElementaryFiles#SUBSCRIPTION_ID
+ * @see ElementaryFiles#EF_TYPE
+ * @see #RECORD_NUMBER
*/
@NonNull
public static Uri getItemUri(
@@ -287,7 +359,28 @@ public final class SimPhonebookContract {
}
- /** Constants for metadata about the elementary files of the SIM cards in the phone. */
+ /**
+ * Constants for metadata about the elementary files of the SIM cards in the phone.
+ *
+ * <h3>Operations </h3>
+ * <dl>
+ * <dd><b>Insert</b></dd>
+ * <p>Insert is not supported for the Uris defined in this class.</p>
+ * <dd><b>Update</b></dd>
+ * <p>Update is not supported for the Uris defined in this class.</p>
+ * <dd><b>Delete</b></dd>
+ * <p>Delete is not supported for the Uris defined in this class.</p>
+ * <dd><b>Query</b></dd>
+ * <p>
+ * The elementary files for all the inserted SIMs can be read via
+ * {@link ElementaryFiles#CONTENT_URI}. Unsupported elementary files are omitted from the
+ * results. This Uri always returns all supported elementary files for all available SIMs; it
+ * does not support filtering via a selection. A specific elementary file can be queried
+ * via a Uri returned by {@link ElementaryFiles#getItemUri(int, int)}. If the elementary file
+ * referenced by this Uri is unsupported by the SIM then the query will return an empty cursor.
+ * </p>
+ * </dl>
+ */
public static final class ElementaryFiles {
/** {@link SubscriptionInfo#getSimSlotIndex()} of the SIM for this row. */
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index b22921233f05..2b577d04b18d 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -46,6 +46,9 @@ public class FeatureFlagUtils {
"settings_do_not_restore_preserved";
/** @hide */
public static final String SETTINGS_PROVIDER_MODEL = "settings_provider_model";
+ /** @hide */
+ public static final String SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES
+ = "settings_use_new_backup_eligibility_rules";
private static final Map<String, String> DEFAULT_FLAGS;
@@ -68,6 +71,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put("settings_silky_home", "false");
DEFAULT_FLAGS.put("settings_contextual_home", "false");
DEFAULT_FLAGS.put(SETTINGS_PROVIDER_MODEL, "false");
+ DEFAULT_FLAGS.put(SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES, "false");
}
private static final Set<String> PERSISTENT_FLAGS;
diff --git a/core/java/android/util/RotationUtils.java b/core/java/android/util/RotationUtils.java
index 698cb77947cf..0ac2c9c25ad1 100644
--- a/core/java/android/util/RotationUtils.java
+++ b/core/java/android/util/RotationUtils.java
@@ -24,6 +24,7 @@ import static android.view.Surface.ROTATION_90;
import android.annotation.Dimension;
import android.graphics.Insets;
import android.graphics.Matrix;
+import android.graphics.Rect;
import android.view.Surface.Rotation;
/**
@@ -73,6 +74,60 @@ public class RotationUtils {
}
/**
+ * Rotates bounds as if parentBounds and bounds are a group. The group is rotated from
+ * oldRotation to newRotation. This assumes that parentBounds is at 0,0 and remains at 0,0 after
+ * rotation. The bounds will be at the same physical position in parentBounds.
+ *
+ * Only 'inOutBounds' is mutated.
+ */
+ public static void rotateBounds(Rect inOutBounds, Rect parentBounds, @Rotation int oldRotation,
+ @Rotation int newRotation) {
+ rotateBounds(inOutBounds, parentBounds, deltaRotation(oldRotation, newRotation));
+ }
+
+ /**
+ * Rotates bounds as if parentBounds and bounds are a group. The group is rotated by `delta`
+ * 90-degree counter-clockwise increments. This assumes that parentBounds is at 0,0 and
+ * remains at 0,0 after rotation. The bounds will be at the same physical position in
+ * parentBounds.
+ *
+ * Only 'inOutBounds' is mutated.
+ */
+ public static void rotateBounds(Rect inOutBounds, Rect parentBounds, @Rotation int rotation) {
+ final int origLeft = inOutBounds.left;
+ final int origTop = inOutBounds.top;
+ switch (rotation) {
+ case ROTATION_0:
+ return;
+ case ROTATION_90:
+ inOutBounds.left = inOutBounds.top;
+ inOutBounds.top = parentBounds.right - inOutBounds.right;
+ inOutBounds.right = inOutBounds.bottom;
+ inOutBounds.bottom = parentBounds.right - origLeft;
+ return;
+ case ROTATION_180:
+ inOutBounds.left = parentBounds.right - inOutBounds.right;
+ inOutBounds.right = parentBounds.right - origLeft;
+ inOutBounds.top = parentBounds.bottom - inOutBounds.bottom;
+ inOutBounds.bottom = parentBounds.bottom - origTop;
+ return;
+ case ROTATION_270:
+ inOutBounds.left = parentBounds.bottom - inOutBounds.bottom;
+ inOutBounds.bottom = inOutBounds.right;
+ inOutBounds.right = parentBounds.bottom - inOutBounds.top;
+ inOutBounds.top = origLeft;
+ }
+ }
+
+ /** @return the rotation needed to rotate from oldRotation to newRotation. */
+ @Rotation
+ public static int deltaRotation(int oldRotation, int newRotation) {
+ int delta = newRotation - oldRotation;
+ if (delta < 0) delta += 4;
+ return delta;
+ }
+
+ /**
* Sets a matrix such that given a rotation, it transforms physical display
* coordinates to that rotation's logical coordinates.
*
diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl
index b9c55081a103..468a69c7bddb 100644
--- a/core/java/android/uwb/IUwbAdapter.aidl
+++ b/core/java/android/uwb/IUwbAdapter.aidl
@@ -17,7 +17,6 @@
package android.uwb;
import android.os.PersistableBundle;
-import android.uwb.AngleOfArrivalSupport;
import android.uwb.IUwbAdapterStateCallbacks;
import android.uwb.IUwbRangingCallbacks;
import android.uwb.SessionHandle;
@@ -47,43 +46,6 @@ interface IUwbAdapter {
void unregisterAdapterStateCallbacks(in IUwbAdapterStateCallbacks callbacks);
/**
- * Returns true if ranging is supported, false otherwise
- */
- boolean isRangingSupported();
-
- /**
- * Get the angle of arrival supported by this device
- *
- * @return the angle of arrival type supported
- */
- AngleOfArrivalSupport getAngleOfArrivalSupport();
-
- /**
- * Generates a list of the supported 802.15.4z channels
- *
- * The list must be prioritized in the order of preferred channel usage.
- *
- * The list must only contain channels that are permitted to be used in the
- * device's current location.
- *
- * @return an array of support channels on the device for the current location.
- */
- int[] getSupportedChannels();
-
- /**
- * Generates a list of the supported 802.15.4z preamble codes
- *
- * The list must be prioritized in the order of preferred preamble usage.
- *
- * The list must only contain preambles that are permitted to be used in the
- * device's current location.
- *
- * @return an array of supported preambles on the device for the current
- * location.
- */
- int[] getSupportedPreambleCodes();
-
- /**
* Get the accuracy of the ranging timestamps
*
* @return accuracy of the ranging timestamps in nanoseconds
@@ -91,27 +53,6 @@ interface IUwbAdapter {
long getTimestampResolutionNanos();
/**
- * Get the supported number of simultaneous ranging sessions
- *
- * @return the supported number of simultaneous ranging sessions
- */
- int getMaxSimultaneousSessions();
-
- /**
- * Get the maximum number of remote devices per session when local device is initiator
- *
- * @return the maximum number of remote devices supported in a single session
- */
- int getMaxRemoteDevicesPerInitiatorSession();
-
- /**
- * Get the maximum number of remote devices per session when local device is responder
- *
- * @return the maximum number of remote devices supported in a single session
- */
- int getMaxRemoteDevicesPerResponderSession();
-
- /**
* Provides the capabilities and features of the device
*
* @return specification specific capabilities and features of the device
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index 2dc0ba0b9b80..63a6d058f358 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -32,10 +32,6 @@ import android.os.ServiceManager;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
import java.util.concurrent.Executor;
/**
@@ -195,133 +191,6 @@ public final class UwbManager {
}
/**
- * Check if ranging is supported, regardless of ranging method
- *
- * @return true if ranging is supported
- */
- @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
- public boolean isRangingSupported() {
- try {
- return mUwbAdapter.isRangingSupported();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE,
- ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D,
- ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL,
- ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL})
- public @interface AngleOfArrivalSupportType {}
-
- /**
- * Indicate absence of support for angle of arrival measurement
- */
- public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE = 1;
-
- /**
- * Indicate support for planar angle of arrival measurement, due to antenna
- * limitation. Typically requires at least two antennas.
- */
- public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D = 2;
-
- /**
- * Indicate support for three dimensional angle of arrival measurement.
- * Typically requires at least three antennas. However, due to antenna
- * arrangement, a platform may only support hemi-spherical azimuth angles
- * ranging from -pi/2 to pi/2
- */
- public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 3;
-
- /**
- * Indicate support for three dimensional angle of arrival measurement.
- * Typically requires at least three antennas. This mode supports full
- * azimuth angles ranging from -pi to pi.
- */
- public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 4;
-
- /**
- * Gets the {@link AngleOfArrivalSupportType} supported on this platform
- * <p>Possible return values are
- * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE},
- * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D},
- * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL},
- * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL}.
- *
- * @return angle of arrival type supported
- */
- @AngleOfArrivalSupportType
- @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
- public int getAngleOfArrivalSupport() {
- try {
- switch (mUwbAdapter.getAngleOfArrivalSupport()) {
- case AngleOfArrivalSupport.TWO_DIMENSIONAL:
- return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D;
-
- case AngleOfArrivalSupport.THREE_DIMENSIONAL_HEMISPHERICAL:
- return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL;
-
- case AngleOfArrivalSupport.THREE_DIMENSIONAL_SPHERICAL:
- return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL;
-
- case AngleOfArrivalSupport.NONE:
- default:
- return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE;
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Get a {@link List} of supported channel numbers based on the device's current location
- * <p>The returned values are ordered by the system's desired ordered of use, with the first
- * entry being the most preferred.
- *
- * <p>Channel numbers are defined based on the IEEE 802.15.4z standard for UWB.
- *
- * @return {@link List} of supported channel numbers ordered by preference
- */
- @NonNull
- @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
- public List<Integer> getSupportedChannelNumbers() {
- List<Integer> channels = new ArrayList<>();
- try {
- for (int channel : mUwbAdapter.getSupportedChannels()) {
- channels.add(channel);
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- return channels;
- }
-
- /**
- * Get a {@link List} of supported preamble code indices
- * <p> Preamble code indices are defined based on the IEEE 802.15.4z standard for UWB.
- *
- * @return {@link List} of supported preamble code indices
- */
- @NonNull
- @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
- public Set<Integer> getSupportedPreambleCodeIndices() {
- Set<Integer> preambles = new HashSet<>();
- try {
- for (int preamble : mUwbAdapter.getSupportedPreambleCodes()) {
- preambles.add(preamble);
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- return preambles;
- }
-
- /**
* Get the timestamp resolution for events in nanoseconds
* <p>This value defines the maximum error of all timestamps for events reported to
* {@link RangingSession.Callback}.
@@ -339,50 +208,6 @@ public final class UwbManager {
}
/**
- * Get the number of simultaneous sessions allowed in the system
- *
- * @return the maximum allowed number of simultaneously open {@link RangingSession} instances.
- */
- @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
- public int getMaxSimultaneousSessions() {
- try {
- return mUwbAdapter.getMaxSimultaneousSessions();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Get the maximum number of remote devices in a {@link RangingSession} when the local device
- * is the initiator.
- *
- * @return the maximum number of remote devices per {@link RangingSession}
- */
- @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
- public int getMaxRemoteDevicesPerInitiatorSession() {
- try {
- return mUwbAdapter.getMaxRemoteDevicesPerInitiatorSession();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Get the maximum number of remote devices in a {@link RangingSession} when the local device
- * is a responder.
- *
- * @return the maximum number of remote devices per {@link RangingSession}
- */
- @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
- public int getMaxRemoteDevicesPerResponderSession() {
- try {
- return mUwbAdapter.getMaxRemoteDevicesPerResponderSession();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Open a {@link RangingSession} with the given parameters
* <p>The {@link RangingSession.Callback#onOpened(RangingSession)} function is called with a
* {@link RangingSession} object used to control ranging when the session is successfully
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 8117c963b959..0ba1dfee16f3 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -34,7 +34,6 @@ import android.graphics.ColorSpace;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
-import android.hardware.display.DeviceProductInfo;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Build;
@@ -1182,18 +1181,6 @@ public final class Display {
}
/**
- * Returns the product-specific information about the display or the directly connected
- * device on the display chain.
- * For example, if the display is transitively connected, this field may contain product
- * information about the intermediate device.
- * Returns {@code null} if product information is not available.
- */
- @Nullable
- public DeviceProductInfo getDeviceProductInfo() {
- return mDisplayInfo.deviceProductInfo;
- }
-
- /**
* Gets display metrics that describe the size and density of this display.
* The size returned by this method does not necessarily represent the
* actual raw size (native resolution) of the display.
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index 6543de15f969..eb49e52d5050 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -213,8 +213,7 @@ public final class FrameMetrics {
Index.FRAME_TIMELINE_VSYNC_ID,
Index.INTENDED_VSYNC,
Index.VSYNC,
- Index.OLDEST_INPUT_EVENT,
- Index.NEWEST_INPUT_EVENT,
+ Index.INPUT_EVENT_ID,
Index.HANDLE_INPUT_START,
Index.ANIMATION_START,
Index.PERFORM_TRAVERSALS_START,
@@ -225,8 +224,11 @@ public final class FrameMetrics {
Index.ISSUE_DRAW_COMMANDS_START,
Index.SWAP_BUFFERS,
Index.FRAME_COMPLETED,
+ Index.DEQUEUE_BUFFER_DURATION,
+ Index.QUEUE_BUFFER_DURATION,
Index.GPU_COMPLETED,
- Index.SWAP_BUFFERS_COMPLETED
+ Index.SWAP_BUFFERS_COMPLETED,
+ Index.DISPLAY_PRESENT_TIME,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Index {
@@ -234,20 +236,22 @@ public final class FrameMetrics {
int FRAME_TIMELINE_VSYNC_ID = 1;
int INTENDED_VSYNC = 2;
int VSYNC = 3;
- int OLDEST_INPUT_EVENT = 4;
- int NEWEST_INPUT_EVENT = 5;
- int HANDLE_INPUT_START = 6;
- int ANIMATION_START = 7;
- int PERFORM_TRAVERSALS_START = 8;
- int DRAW_START = 9;
- int FRAME_DEADLINE = 10;
- int SYNC_QUEUED = 11;
- int SYNC_START = 12;
- int ISSUE_DRAW_COMMANDS_START = 13;
- int SWAP_BUFFERS = 14;
- int FRAME_COMPLETED = 15;
- int GPU_COMPLETED = 18;
- int SWAP_BUFFERS_COMPLETED = 19;
+ int INPUT_EVENT_ID = 4;
+ int HANDLE_INPUT_START = 5;
+ int ANIMATION_START = 6;
+ int PERFORM_TRAVERSALS_START = 7;
+ int DRAW_START = 8;
+ int FRAME_DEADLINE = 9;
+ int SYNC_QUEUED = 10;
+ int SYNC_START = 11;
+ int ISSUE_DRAW_COMMANDS_START = 12;
+ int SWAP_BUFFERS = 13;
+ int FRAME_COMPLETED = 14;
+ int DEQUEUE_BUFFER_DURATION = 15;
+ int QUEUE_BUFFER_DURATION = 16;
+ int GPU_COMPLETED = 17;
+ int SWAP_BUFFERS_COMPLETED = 18;
+ int DISPLAY_PRESENT_TIME = 19;
int FRAME_STATS_COUNT = 20; // must always be last and in sync with
// FrameInfoIndex::NumIndexes in libs/hwui/FrameInfo.h
diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedTaskListener.aidl
index 29c9c155e978..c31e67e59a99 100644
--- a/core/java/android/view/IPinnedStackListener.aidl
+++ b/core/java/android/view/IPinnedTaskListener.aidl
@@ -23,11 +23,11 @@ import android.graphics.Rect;
import android.view.DisplayInfo;
/**
- * Listener for changes to the pinned stack made by the WindowManager.
+ * Listener for changes to the pinned task made by the WindowManager.
*
* @hide
*/
-oneway interface IPinnedStackListener {
+oneway interface IPinnedTaskListener {
/**
* Called when the window manager has detected a change that would cause the movement bounds
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 4e4ba3fad246..afdf798d03ce 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -35,13 +35,12 @@ import android.os.ParcelFileDescriptor;
import android.view.DisplayCutout;
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
-import android.view.IDockedStackListener;
import android.view.IDisplayWindowInsetsController;
import android.view.IDisplayWindowListener;
import android.view.IDisplayFoldListener;
import android.view.IDisplayWindowRotationController;
import android.view.IOnKeyguardExitResult;
-import android.view.IPinnedStackListener;
+import android.view.IPinnedTaskListener;
import android.view.IScrollCaptureCallbacks;
import android.view.RemoteAnimationAdapter;
import android.view.IRotationWatcher;
@@ -446,12 +445,12 @@ interface IWindowManager
* Sets the region the user can touch the divider. This region will be excluded from the region
* which is used to cause a focus switch when dispatching touch.
*/
- void setDockedStackDividerTouchRegion(in Rect touchableRegion);
+ void setDockedTaskDividerTouchRegion(in Rect touchableRegion);
/**
- * Registers a listener that will be called when the pinned stack state changes.
+ * Registers a listener that will be called when the pinned task state changes.
*/
- void registerPinnedStackListener(int displayId, IPinnedStackListener listener);
+ void registerPinnedTaskListener(int displayId, IPinnedTaskListener listener);
/**
* Requests Keyboard Shortcuts from the displayed window.
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 59e493191711..fafb885c58e0 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -26,6 +26,7 @@ import android.hardware.Battery;
import android.hardware.SensorManager;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
+import android.hardware.lights.LightsManager;
import android.os.Build;
import android.os.NullVibrator;
import android.os.Parcel;
@@ -89,6 +90,9 @@ public final class InputDevice implements Parcelable {
@GuardedBy("mMotionRanges")
private Battery mBattery;
+ @GuardedBy("mMotionRanges")
+ private LightsManager mLightsManager;
+
/**
* A mask for input source classes.
*
@@ -859,6 +863,21 @@ public final class InputDevice implements Parcelable {
}
/**
+ * Gets the lights manager associated with the device, if there is one.
+ * Even if the device does not have lights, the result is never null.
+ * Use {@link LightsManager#getLights} to determine whether any lights is
+ * present.
+ *
+ * @return The lights manager associated with the device, never null.
+ */
+ public @NonNull LightsManager getLightsManager() {
+ if (mLightsManager == null) {
+ mLightsManager = InputManager.getInstance().getInputDeviceLightsManager(mId);
+ }
+ return mLightsManager;
+ }
+
+ /**
* Gets the sensor manager service associated with the input device.
* Even if the device does not have a sensor, the result is never null.
* Use {@link SensorManager#getSensorList} to get a full list of all supported sensors.
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 2bd32acc6c2c..0832578d80c5 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -191,9 +191,6 @@ public final class SurfaceControl implements Parcelable {
private static native void nativeReparent(long transactionObj, long nativeObject,
long newParentNativeObject);
- private static native boolean nativeGetAutoLowLatencyModeSupport(IBinder displayToken);
- private static native boolean nativeGetGameContentTypeSupport(IBinder displayToken);
-
private static native void nativeSetInputWindowInfo(long transactionObj, long nativeObject,
InputWindowHandle handle);
@@ -1750,6 +1747,9 @@ public final class SurfaceControl implements Parcelable {
public Display.HdrCapabilities hdrCapabilities;
+ public boolean autoLowLatencyModeSupported;
+ public boolean gameContentTypeSupported;
+
@Override
public String toString() {
return "DynamicDisplayInfo{"
@@ -1757,7 +1757,9 @@ public final class SurfaceControl implements Parcelable {
+ ", activeDisplayModeId=" + activeDisplayModeId
+ ", supportedColorModes=" + Arrays.toString(supportedColorModes)
+ ", activeColorMode=" + activeColorMode
- + ", hdrCapabilities=" + hdrCapabilities + "}";
+ + ", hdrCapabilities=" + hdrCapabilities
+ + ", autoLowLatencyModeSupported=" + autoLowLatencyModeSupported
+ + ", gameContentTypeSupported" + gameContentTypeSupported + "}";
}
@Override
@@ -2204,28 +2206,6 @@ public final class SurfaceControl implements Parcelable {
/**
* @hide
*/
- public static boolean getAutoLowLatencyModeSupport(IBinder displayToken) {
- if (displayToken == null) {
- throw new IllegalArgumentException("displayToken must not be null");
- }
-
- return nativeGetAutoLowLatencyModeSupport(displayToken);
- }
-
- /**
- * @hide
- */
- public static boolean getGameContentTypeSupport(IBinder displayToken) {
- if (displayToken == null) {
- throw new IllegalArgumentException("displayToken must not be null");
- }
-
- return nativeGetGameContentTypeSupport(displayToken);
- }
-
- /**
- * @hide
- */
@UnsupportedAppUsage
public static IBinder createDisplay(String name, boolean secure) {
if (name == null) {
diff --git a/core/java/android/view/SurfaceControlFpsListener.java b/core/java/android/view/SurfaceControlFpsListener.java
new file mode 100644
index 000000000000..517b0fb8ccd3
--- /dev/null
+++ b/core/java/android/view/SurfaceControlFpsListener.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.NonNull;
+
+/**
+ * Listener for sampling the frames per second for a SurfaceControl and its children.
+ * This should only be used by a system component that needs to listen to a SurfaceControl's
+ * tree's FPS when it is not actively submitting transactions for that SurfaceControl.
+ * Otherwise, ASurfaceTransaction_OnComplete callbacks should be used.
+ *
+ * @hide
+ */
+public abstract class SurfaceControlFpsListener {
+ private long mNativeListener;
+
+ public SurfaceControlFpsListener() {
+ mNativeListener = nativeCreate(this);
+ }
+
+ protected void destroy() {
+ if (mNativeListener == 0) {
+ return;
+ }
+ unregister();
+ nativeDestroy(mNativeListener);
+ mNativeListener = 0;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ destroy();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Reports the fps from the registered SurfaceControl
+ */
+ public abstract void onFpsReported(float fps);
+
+ /**
+ * Registers the sampling listener.
+ */
+ public void register(@NonNull SurfaceControl layer) {
+ if (mNativeListener == 0) {
+ return;
+ }
+
+ nativeRegister(mNativeListener, layer.mNativeObject);
+ }
+
+ /**
+ * Unregisters the sampling listener.
+ */
+ public void unregister() {
+ if (mNativeListener == 0) {
+ return;
+ }
+ nativeUnregister(mNativeListener);
+ }
+
+ /**
+ * Dispatch the collected sample.
+ *
+ * Called from native code on a binder thread.
+ */
+ private static void dispatchOnFpsReported(SurfaceControlFpsListener listener, float fps) {
+ listener.onFpsReported(fps);
+ }
+
+ private static native long nativeCreate(SurfaceControlFpsListener thiz);
+ private static native void nativeDestroy(long ptr);
+ private static native void nativeRegister(long ptr, long layerObject);
+ private static native void nativeUnregister(long ptr);
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c46fbc7fb4c4..3789324a038c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6996,6 +6996,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #getScrollIndicators()
* @attr ref android.R.styleable#View_scrollIndicators
*/
+ @RemotableViewMethod
public void setScrollIndicators(@ScrollIndicators int indicators) {
setScrollIndicators(indicators,
SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT);
@@ -11881,6 +11882,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #setFocusable(int)
* @attr ref android.R.styleable#View_focusable
*/
+ @RemotableViewMethod
public void setFocusable(boolean focusable) {
setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE);
}
@@ -11899,6 +11901,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #setFocusableInTouchMode(boolean)
* @attr ref android.R.styleable#View_focusable
*/
+ @RemotableViewMethod
public void setFocusable(@Focusable int focusable) {
if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) {
setFlags(0, FOCUSABLE_IN_TOUCH_MODE);
@@ -11917,6 +11920,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #setFocusable(boolean)
* @attr ref android.R.styleable#View_focusableInTouchMode
*/
+ @RemotableViewMethod
public void setFocusableInTouchMode(boolean focusableInTouchMode) {
// Focusable in touch mode should always be set before the focusable flag
// otherwise, setting the focusable flag will trigger a focusableViewAvailable()
@@ -12871,6 +12875,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_focusedByDefault
*/
+ @RemotableViewMethod
public void setFocusedByDefault(boolean isFocusedByDefault) {
if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) {
return;
@@ -16850,6 +16855,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_rotation
*/
+ @RemotableViewMethod
public void setRotation(float rotation) {
if (rotation != getRotation()) {
// Double-invalidation is necessary to capture view's old and new areas
@@ -16896,6 +16902,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_rotationY
*/
+ @RemotableViewMethod
public void setRotationY(float rotationY) {
if (rotationY != getRotationY()) {
invalidateViewProperty(true, false);
@@ -16941,6 +16948,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_rotationX
*/
+ @RemotableViewMethod
public void setRotationX(float rotationX) {
if (rotationX != getRotationX()) {
invalidateViewProperty(true, false);
@@ -16978,6 +16986,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_scaleX
*/
+ @RemotableViewMethod
public void setScaleX(float scaleX) {
if (scaleX != getScaleX()) {
scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX");
@@ -17016,6 +17025,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_scaleY
*/
+ @RemotableViewMethod
public void setScaleY(float scaleY) {
if (scaleY != getScaleY()) {
scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY");
@@ -17061,6 +17071,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_transformPivotX
*/
+ @RemotableViewMethod
public void setPivotX(float pivotX) {
if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) {
invalidateViewProperty(true, false);
@@ -17103,6 +17114,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_transformPivotY
*/
+ @RemotableViewMethod
public void setPivotY(float pivotY) {
if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) {
invalidateViewProperty(true, false);
@@ -17243,6 +17255,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_alpha
*/
+ @RemotableViewMethod
public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
ensureTransformationInfo();
if (mTransformationInfo.mAlpha != alpha) {
@@ -17732,6 +17745,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_elevation
*/
+ @RemotableViewMethod
public void setElevation(float elevation) {
if (elevation != getElevation()) {
elevation = sanitizeFloatPropertyValue(elevation, "elevation");
@@ -17766,6 +17780,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_translationX
*/
+ @RemotableViewMethod
public void setTranslationX(float translationX) {
if (translationX != getTranslationX()) {
invalidateViewProperty(true, false);
@@ -17801,6 +17816,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_translationY
*/
+ @RemotableViewMethod
public void setTranslationY(float translationY) {
if (translationY != getTranslationY()) {
invalidateViewProperty(true, false);
@@ -17828,6 +17844,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_translationZ
*/
+ @RemotableViewMethod
public void setTranslationZ(float translationZ) {
if (translationZ != getTranslationZ()) {
translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ");
@@ -23989,6 +24006,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #getBackgroundTintList()
* @see Drawable#setTintList(ColorStateList)
*/
+ @RemotableViewMethod
public void setBackgroundTintList(@Nullable ColorStateList tint) {
if (mBackgroundTint == null) {
mBackgroundTint = new TintInfo();
@@ -24248,6 +24266,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #getForegroundTintList()
* @see Drawable#setTintList(ColorStateList)
*/
+ @RemotableViewMethod
public void setForegroundTintList(@Nullable ColorStateList tint) {
if (mForegroundInfo == null) {
mForegroundInfo = new ForegroundInfo();
diff --git a/core/java/android/view/ViewFrameInfo.java b/core/java/android/view/ViewFrameInfo.java
index 890d071f8090..d4aaa611f800 100644
--- a/core/java/android/view/ViewFrameInfo.java
+++ b/core/java/android/view/ViewFrameInfo.java
@@ -58,8 +58,8 @@ public class ViewFrameInfo {
public void populateFrameInfo(FrameInfo frameInfo) {
frameInfo.frameInfo[FrameInfo.FLAGS] |= flags;
frameInfo.frameInfo[FrameInfo.DRAW_START] = drawStart;
- frameInfo.frameInfo[FrameInfo.OLDEST_INPUT_EVENT] = oldestInputEventTime;
- frameInfo.frameInfo[FrameInfo.NEWEST_INPUT_EVENT] = newestInputEventTime;
+ // TODO(b/169866723): Use InputEventAssigner
+ frameInfo.frameInfo[FrameInfo.INPUT_EVENT_ID] = newestInputEventTime;
}
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f1f6786aa43e..144691d3eaa0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1677,7 +1677,8 @@ public final class ViewRootImpl implements ViewParent,
// See comment for View.sForceLayoutWhenInsetsChanged
if (View.sForceLayoutWhenInsetsChanged && mView != null
- && mWindowAttributes.softInputMode == SOFT_INPUT_ADJUST_RESIZE) {
+ && (mWindowAttributes.softInputMode & SOFT_INPUT_MASK_ADJUST)
+ == SOFT_INPUT_ADJUST_RESIZE) {
forceLayout(mView);
}
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index de4554b9e624..6ade5e622eab 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -105,7 +105,7 @@ public interface InputMethod {
*/
@MainThread
default void initializeInternal(IBinder token, int displayId,
- IInputMethodPrivilegedOperations privilegedOperations) {
+ IInputMethodPrivilegedOperations privilegedOperations, int configChanges) {
updateInputMethodDisplay(displayId);
attachToken(token);
}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 5d876a6f62d3..25712f8bf9b8 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -18,19 +18,23 @@ package android.view.inputmethod;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
+import android.inputmethodservice.InputMethodService;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
@@ -60,6 +64,7 @@ import java.util.List;
* @attr ref android.R.styleable#InputMethod_isDefault
* @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod
* @attr ref android.R.styleable#InputMethod_supportsInlineSuggestions
+ * @attr ref android.R.styleable#InputMethod_configChanges
*/
public final class InputMethodInfo implements Parcelable {
static final String TAG = "InputMethodInfo";
@@ -118,6 +123,12 @@ public final class InputMethodInfo implements Parcelable {
private final boolean mInlineSuggestionsEnabled;
/**
+ * The flag for configurations IME assumes the responsibility for handling in
+ * {@link InputMethodService#onConfigurationChanged(Configuration)}}.
+ */
+ private final int mHandledConfigChanges;
+
+ /**
* @param service the {@link ResolveInfo} corresponds in which the IME is implemented.
* @return a unique ID to be returned by {@link #getId()}. We have used
* {@link ComponentName#flattenToShortString()} for this purpose (and it is already
@@ -203,6 +214,8 @@ public final class InputMethodInfo implements Parcelable {
false);
inlineSuggestionsEnabled = sa.getBoolean(
com.android.internal.R.styleable.InputMethod_supportsInlineSuggestions, false);
+ mHandledConfigChanges = sa.getInt(
+ com.android.internal.R.styleable.InputMethod_configChanges, 0);
sa.recycle();
final int depth = parser.getDepth();
@@ -287,6 +300,7 @@ public final class InputMethodInfo implements Parcelable {
mIsVrOnly = source.readBoolean();
mService = ResolveInfo.CREATOR.createFromParcel(source);
mSubtypes = new InputMethodSubtypeArray(source);
+ mHandledConfigChanges = source.readInt();
mForceDefault = false;
}
@@ -298,7 +312,22 @@ public final class InputMethodInfo implements Parcelable {
this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
- false /* inlineSuggestionsEnabled */, false /* isVrOnly */);
+ false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
+ 0 /* handledConfigChanges */);
+ }
+
+ /**
+ * Temporary API for creating a built-in input method for test.
+ * @hide
+ */
+ @TestApi
+ public InputMethodInfo(@NonNull String packageName, @NonNull String className,
+ @NonNull CharSequence label, @NonNull String settingsActivity,
+ int handledConfigChanges) {
+ this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
+ settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
+ false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
+ false /* inlineSuggestionsEnabled */, false /* isVrOnly */, handledConfigChanges);
}
/**
@@ -310,7 +339,7 @@ public final class InputMethodInfo implements Parcelable {
boolean forceDefault) {
this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
true /* supportsSwitchingToNextInputMethod */, false /* inlineSuggestionsEnabled */,
- false /* isVrOnly */);
+ false /* isVrOnly */, 0 /* handledconfigChanges */);
}
/**
@@ -321,7 +350,8 @@ public final class InputMethodInfo implements Parcelable {
List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
boolean supportsSwitchingToNextInputMethod, boolean isVrOnly) {
this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
- supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly);
+ supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly,
+ 0 /* handledConfigChanges */);
}
/**
@@ -331,7 +361,7 @@ public final class InputMethodInfo implements Parcelable {
public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity,
List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled,
- boolean isVrOnly) {
+ boolean isVrOnly, int handledConfigChanges) {
final ServiceInfo si = ri.serviceInfo;
mService = ri;
mId = new ComponentName(si.packageName, si.name).flattenToShortString();
@@ -343,6 +373,7 @@ public final class InputMethodInfo implements Parcelable {
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
mIsVrOnly = isVrOnly;
+ mHandledConfigChanges = handledConfigChanges;
}
private static ResolveInfo buildFakeResolveInfo(String packageName, String className,
@@ -489,6 +520,17 @@ public final class InputMethodInfo implements Parcelable {
}
}
+ /**
+ * Returns the bit mask of kinds of configuration changes that this IME
+ * can handle itself (without being restarted by the system).
+ *
+ * @attr ref android.R.styleable#InputMethod_configChanges
+ */
+ @ActivityInfo.Config
+ public int getConfigChanges() {
+ return mHandledConfigChanges;
+ }
+
public void dump(Printer pw, String prefix) {
pw.println(prefix + "mId=" + mId
+ " mSettingsActivityName=" + mSettingsActivityName
@@ -579,6 +621,7 @@ public final class InputMethodInfo implements Parcelable {
dest.writeBoolean(mIsVrOnly);
mService.writeToParcel(dest, flags);
mSubtypes.writeToParcel(dest);
+ dest.writeInt(mHandledConfigChanges);
}
/**
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 05b177ebbb45..39c09b46f2e1 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -6612,6 +6612,27 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
/**
+ * Returns the {@link EdgeEffect#getType()} for the edge effects.
+ * @return the {@link EdgeEffect#getType()} for the edge effects.
+ * @attr ref android.R.styleable#EdgeEffect_edgeEffectType
+ */
+ @EdgeEffect.EdgeEffectType
+ public int getEdgeEffectType() {
+ return mEdgeGlowTop.getType();
+ }
+
+ /**
+ * Sets the {@link EdgeEffect#setType(int)} for the edge effects.
+ * @param type The edge effect type to use for the edge effects.
+ * @attr ref android.R.styleable#EdgeEffect_edgeEffectType
+ */
+ public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) {
+ mEdgeGlowTop.setType(type);
+ mEdgeGlowBottom.setType(type);
+ invalidate();
+ }
+
+ /**
* Sets the recycler listener to be notified whenever a View is set aside in
* the recycler for later reuse. This listener can be used to free resources
* associated to the View.
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 93b2d8ae3c9a..34fe51e82e8f 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -23,8 +23,10 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
@@ -68,12 +70,16 @@ public class AnalogClock extends View {
@UnsupportedAppUsage
private Drawable mHourHand;
+ private final TintInfo mHourHandTintInfo = new TintInfo();
@UnsupportedAppUsage
private Drawable mMinuteHand;
+ private final TintInfo mMinuteHandTintInfo = new TintInfo();
@Nullable
private Drawable mSecondHand;
+ private final TintInfo mSecondHandTintInfo = new TintInfo();
@UnsupportedAppUsage
private Drawable mDial;
+ private final TintInfo mDialTintInfo = new TintInfo();
private int mDialWidth;
private int mDialHeight;
@@ -111,18 +117,86 @@ public class AnalogClock extends View {
mDial = context.getDrawable(com.android.internal.R.drawable.clock_dial);
}
+ ColorStateList dialTintList = a.getColorStateList(
+ com.android.internal.R.styleable.AnalogClock_dialTint);
+ if (dialTintList != null) {
+ mDialTintInfo.mTintList = dialTintList;
+ mDialTintInfo.mHasTintList = true;
+ }
+ BlendMode dialTintMode = Drawable.parseBlendMode(
+ a.getInt(com.android.internal.R.styleable.AnalogClock_dialTintMode, -1),
+ null);
+ if (dialTintMode != null) {
+ mDialTintInfo.mTintBlendMode = dialTintMode;
+ mDialTintInfo.mHasTintBlendMode = true;
+ }
+ if (mDialTintInfo.mHasTintList || mDialTintInfo.mHasTintBlendMode) {
+ mDial = mDialTintInfo.apply(mDial);
+ }
+
mHourHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_hour);
if (mHourHand == null) {
mHourHand = context.getDrawable(com.android.internal.R.drawable.clock_hand_hour);
}
+ ColorStateList hourHandTintList = a.getColorStateList(
+ com.android.internal.R.styleable.AnalogClock_hand_hourTint);
+ if (hourHandTintList != null) {
+ mHourHandTintInfo.mTintList = hourHandTintList;
+ mHourHandTintInfo.mHasTintList = true;
+ }
+ BlendMode hourHandTintMode = Drawable.parseBlendMode(
+ a.getInt(com.android.internal.R.styleable.AnalogClock_hand_hourTintMode, -1),
+ null);
+ if (hourHandTintMode != null) {
+ mHourHandTintInfo.mTintBlendMode = hourHandTintMode;
+ mHourHandTintInfo.mHasTintBlendMode = true;
+ }
+ if (mHourHandTintInfo.mHasTintList || mHourHandTintInfo.mHasTintBlendMode) {
+ mHourHand = mHourHandTintInfo.apply(mHourHand);
+ }
+
mMinuteHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_minute);
if (mMinuteHand == null) {
mMinuteHand = context.getDrawable(com.android.internal.R.drawable.clock_hand_minute);
}
+ ColorStateList minuteHandTintList = a.getColorStateList(
+ com.android.internal.R.styleable.AnalogClock_hand_minuteTint);
+ if (minuteHandTintList != null) {
+ mMinuteHandTintInfo.mTintList = minuteHandTintList;
+ mMinuteHandTintInfo.mHasTintList = true;
+ }
+ BlendMode minuteHandTintMode = Drawable.parseBlendMode(
+ a.getInt(com.android.internal.R.styleable.AnalogClock_hand_minuteTintMode, -1),
+ null);
+ if (minuteHandTintMode != null) {
+ mMinuteHandTintInfo.mTintBlendMode = minuteHandTintMode;
+ mMinuteHandTintInfo.mHasTintBlendMode = true;
+ }
+ if (mMinuteHandTintInfo.mHasTintList || mMinuteHandTintInfo.mHasTintBlendMode) {
+ mMinuteHand = mMinuteHandTintInfo.apply(mMinuteHand);
+ }
+
mSecondHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_second);
+ ColorStateList secondHandTintList = a.getColorStateList(
+ com.android.internal.R.styleable.AnalogClock_hand_secondTint);
+ if (secondHandTintList != null) {
+ mSecondHandTintInfo.mTintList = secondHandTintList;
+ mSecondHandTintInfo.mHasTintList = true;
+ }
+ BlendMode secondHandTintMode = Drawable.parseBlendMode(
+ a.getInt(com.android.internal.R.styleable.AnalogClock_hand_secondTintMode, -1),
+ null);
+ if (secondHandTintMode != null) {
+ mSecondHandTintInfo.mTintBlendMode = secondHandTintMode;
+ mSecondHandTintInfo.mHasTintBlendMode = true;
+ }
+ if (mSecondHandTintInfo.mHasTintList || mSecondHandTintInfo.mHasTintBlendMode) {
+ mSecondHand = mSecondHandTintInfo.apply(mSecondHand);
+ }
+
mTimeZone = toZoneId(a.getString(com.android.internal.R.styleable.AnalogClock_timeZone));
createClock();
@@ -141,6 +215,68 @@ public class AnalogClock extends View {
invalidate();
}
+ /**
+ * Applies a tint to the dial drawable.
+ * <p>
+ * Subsequent calls to {@link #setDial(Icon)} will
+ * automatically mutate the drawable and apply the specified tint and tint
+ * mode using {@link Drawable#setTintList(ColorStateList)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#AnalogClock_dialTint
+ * @see #getDialTintList()
+ * @see Drawable#setTintList(ColorStateList)
+ */
+ @RemotableViewMethod
+ public void setDialTintList(@Nullable ColorStateList tint) {
+ mDialTintInfo.mTintList = tint;
+ mDialTintInfo.mHasTintList = true;
+
+ mDial = mDialTintInfo.apply(mDial);
+ }
+
+ /**
+ * @return the tint applied to the dial drawable
+ * @attr ref android.R.styleable#AnalogClock_dialTint
+ * @see #setDialTintList(ColorStateList)
+ */
+ @InspectableProperty(attributeId = com.android.internal.R.styleable.AnalogClock_dialTint)
+ @Nullable
+ public ColorStateList getDialTintList() {
+ return mDialTintInfo.mTintList;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setDialTintList(ColorStateList)}} to the dial drawable.
+ * The default mode is {@link BlendMode#SRC_IN}.
+ *
+ * @param blendMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#AnalogClock_dialTintMode
+ * @see #getDialTintBlendMode()
+ * @see Drawable#setTintBlendMode(BlendMode)
+ */
+ @RemotableViewMethod
+ public void setDialTintBlendMode(@Nullable BlendMode blendMode) {
+ mDialTintInfo.mTintBlendMode = blendMode;
+ mDialTintInfo.mHasTintBlendMode = true;
+
+ mDial = mDialTintInfo.apply(mDial);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the dial drawable
+ * @attr ref android.R.styleable#AnalogClock_dialTintMode
+ * @see #setDialTintBlendMode(BlendMode)
+ */
+ @InspectableProperty(attributeId = com.android.internal.R.styleable.AnalogClock_dialTintMode)
+ @Nullable
+ public BlendMode getDialTintBlendMode() {
+ return mDialTintInfo.mTintBlendMode;
+ }
+
/** Sets the hour hand of the clock to the specified Icon. */
@RemotableViewMethod
public void setHourHand(@NonNull Icon icon) {
@@ -150,6 +286,71 @@ public class AnalogClock extends View {
invalidate();
}
+ /**
+ * Applies a tint to the hour hand drawable.
+ * <p>
+ * Subsequent calls to {@link #setHourHand(Icon)} will
+ * automatically mutate the drawable and apply the specified tint and tint
+ * mode using {@link Drawable#setTintList(ColorStateList)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#AnalogClock_hand_hourTint
+ * @see #getHourHandTintList()
+ * @see Drawable#setTintList(ColorStateList)
+ */
+ @RemotableViewMethod
+ public void setHourHandTintList(@Nullable ColorStateList tint) {
+ mHourHandTintInfo.mTintList = tint;
+ mHourHandTintInfo.mHasTintList = true;
+
+ mHourHand = mHourHandTintInfo.apply(mHourHand);
+ }
+
+ /**
+ * @return the tint applied to the hour hand drawable
+ * @attr ref android.R.styleable#AnalogClock_hand_hourTint
+ * @see #setHourHandTintList(ColorStateList)
+ */
+ @InspectableProperty(
+ attributeId = com.android.internal.R.styleable.AnalogClock_hand_hourTint
+ )
+ @Nullable
+ public ColorStateList getHourHandTintList() {
+ return mHourHandTintInfo.mTintList;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setHourHandTintList(ColorStateList)}} to the hour hand drawable.
+ * The default mode is {@link BlendMode#SRC_IN}.
+ *
+ * @param blendMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#AnalogClock_hand_hourTintMode
+ * @see #getHourHandTintBlendMode()
+ * @see Drawable#setTintBlendMode(BlendMode)
+ */
+ @RemotableViewMethod
+ public void setHourHandTintBlendMode(@Nullable BlendMode blendMode) {
+ mHourHandTintInfo.mTintBlendMode = blendMode;
+ mHourHandTintInfo.mHasTintBlendMode = true;
+
+ mHourHand = mHourHandTintInfo.apply(mHourHand);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the hour hand drawable
+ * @attr ref android.R.styleable#AnalogClock_hand_hourTintMode
+ * @see #setHourHandTintBlendMode(BlendMode)
+ */
+ @InspectableProperty(
+ attributeId = com.android.internal.R.styleable.AnalogClock_hand_hourTintMode)
+ @Nullable
+ public BlendMode getHourHandTintBlendMode() {
+ return mHourHandTintInfo.mTintBlendMode;
+ }
+
/** Sets the minute hand of the clock to the specified Icon. */
@RemotableViewMethod
public void setMinuteHand(@NonNull Icon icon) {
@@ -160,6 +361,71 @@ public class AnalogClock extends View {
}
/**
+ * Applies a tint to the minute hand drawable.
+ * <p>
+ * Subsequent calls to {@link #setMinuteHand(Icon)} will
+ * automatically mutate the drawable and apply the specified tint and tint
+ * mode using {@link Drawable#setTintList(ColorStateList)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#AnalogClock_hand_minuteTint
+ * @see #getMinuteHandTintList()
+ * @see Drawable#setTintList(ColorStateList)
+ */
+ @RemotableViewMethod
+ public void setMinuteHandTintList(@Nullable ColorStateList tint) {
+ mMinuteHandTintInfo.mTintList = tint;
+ mMinuteHandTintInfo.mHasTintList = true;
+
+ mMinuteHand = mMinuteHandTintInfo.apply(mMinuteHand);
+ }
+
+ /**
+ * @return the tint applied to the minute hand drawable
+ * @attr ref android.R.styleable#AnalogClock_hand_minuteTint
+ * @see #setMinuteHandTintList(ColorStateList)
+ */
+ @InspectableProperty(
+ attributeId = com.android.internal.R.styleable.AnalogClock_hand_minuteTint
+ )
+ @Nullable
+ public ColorStateList getMinuteHandTintList() {
+ return mMinuteHandTintInfo.mTintList;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setMinuteHandTintList(ColorStateList)}} to the minute hand drawable.
+ * The default mode is {@link BlendMode#SRC_IN}.
+ *
+ * @param blendMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#AnalogClock_hand_minuteTintMode
+ * @see #getMinuteHandTintBlendMode()
+ * @see Drawable#setTintBlendMode(BlendMode)
+ */
+ @RemotableViewMethod
+ public void setMinuteHandTintBlendMode(@Nullable BlendMode blendMode) {
+ mMinuteHandTintInfo.mTintBlendMode = blendMode;
+ mMinuteHandTintInfo.mHasTintBlendMode = true;
+
+ mMinuteHand = mMinuteHandTintInfo.apply(mMinuteHand);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the minute hand drawable
+ * @attr ref android.R.styleable#AnalogClock_hand_minuteTintMode
+ * @see #setMinuteHandTintBlendMode(BlendMode)
+ */
+ @InspectableProperty(
+ attributeId = com.android.internal.R.styleable.AnalogClock_hand_minuteTintMode)
+ @Nullable
+ public BlendMode getMinuteHandTintBlendMode() {
+ return mMinuteHandTintInfo.mTintBlendMode;
+ }
+
+ /**
* Sets the second hand of the clock to the specified Icon, or hides the second hand if it is
* null.
*/
@@ -173,6 +439,71 @@ public class AnalogClock extends View {
}
/**
+ * Applies a tint to the second hand drawable.
+ * <p>
+ * Subsequent calls to {@link #setSecondHand(Icon)} will
+ * automatically mutate the drawable and apply the specified tint and tint
+ * mode using {@link Drawable#setTintList(ColorStateList)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#AnalogClock_hand_secondTint
+ * @see #getSecondHandTintList()
+ * @see Drawable#setTintList(ColorStateList)
+ */
+ @RemotableViewMethod
+ public void setSecondHandTintList(@Nullable ColorStateList tint) {
+ mSecondHandTintInfo.mTintList = tint;
+ mSecondHandTintInfo.mHasTintList = true;
+
+ mSecondHand = mSecondHandTintInfo.apply(mSecondHand);
+ }
+
+ /**
+ * @return the tint applied to the second hand drawable
+ * @attr ref android.R.styleable#AnalogClock_hand_secondTint
+ * @see #setSecondHandTintList(ColorStateList)
+ */
+ @InspectableProperty(
+ attributeId = com.android.internal.R.styleable.AnalogClock_hand_secondTint
+ )
+ @Nullable
+ public ColorStateList getSecondHandTintList() {
+ return mSecondHandTintInfo.mTintList;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setSecondHandTintList(ColorStateList)}} to the second hand drawable.
+ * The default mode is {@link BlendMode#SRC_IN}.
+ *
+ * @param blendMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#AnalogClock_hand_secondTintMode
+ * @see #getSecondHandTintBlendMode()
+ * @see Drawable#setTintBlendMode(BlendMode)
+ */
+ @RemotableViewMethod
+ public void setSecondHandTintBlendMode(@Nullable BlendMode blendMode) {
+ mSecondHandTintInfo.mTintBlendMode = blendMode;
+ mSecondHandTintInfo.mHasTintBlendMode = true;
+
+ mSecondHand = mSecondHandTintInfo.apply(mSecondHand);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the second hand drawable
+ * @attr ref android.R.styleable#AnalogClock_hand_secondTintMode
+ * @see #setSecondHandTintBlendMode(BlendMode)
+ */
+ @InspectableProperty(
+ attributeId = com.android.internal.R.styleable.AnalogClock_hand_secondTintMode)
+ @Nullable
+ public BlendMode getSecondHandTintBlendMode() {
+ return mSecondHandTintInfo.mTintBlendMode;
+ }
+
+ /**
* Indicates which time zone is currently used by this view.
*
* @return The ID of the current time zone or null if the default time zone,
@@ -462,4 +793,36 @@ public class AnalogClock extends View {
return null;
}
}
+
+ private final class TintInfo {
+ boolean mHasTintList;
+ @Nullable ColorStateList mTintList;
+ boolean mHasTintBlendMode;
+ @Nullable BlendMode mTintBlendMode;
+
+ /**
+ * Returns a mutated copy of {@code drawable} with tinting applied, or null if it's null.
+ */
+ @Nullable
+ Drawable apply(@Nullable Drawable drawable) {
+ if (drawable == null) return null;
+
+ Drawable newDrawable = drawable.mutate();
+
+ if (mHasTintList) {
+ newDrawable.setTintList(mTintList);
+ }
+
+ if (mHasTintBlendMode) {
+ newDrawable.setTintBlendMode(mTintBlendMode);
+ }
+
+ // All drawables should have the same state as the View itself.
+ if (drawable.isStateful()) {
+ newDrawable.setState(getDrawableState());
+ }
+
+ return newDrawable;
+ }
+ }
}
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 6dedd12a2730..23915e06335a 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -303,6 +303,27 @@ public class HorizontalScrollView extends FrameLayout {
}
/**
+ * Returns the {@link EdgeEffect#getType()} for the edge effects.
+ * @return the {@link EdgeEffect#getType()} for the edge effects.
+ * @attr ref android.R.styleable#EdgeEffect_edgeEffectType
+ */
+ @EdgeEffect.EdgeEffectType
+ public int getEdgeEffectType() {
+ return mEdgeGlowLeft.getType();
+ }
+
+ /**
+ * Sets the {@link EdgeEffect#setType(int)} for the edge effects.
+ * @param type The edge effect type to use for the edge effects.
+ * @attr ref android.R.styleable#EdgeEffect_edgeEffectType
+ */
+ public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) {
+ mEdgeGlowRight.setType(type);
+ mEdgeGlowLeft.setType(type);
+ invalidate();
+ }
+
+ /**
* @return The maximum amount this scroll view will scroll in response to
* an arrow event.
*/
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 0a08ccd34f02..8aa557bab4e3 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -648,6 +648,7 @@ public class ImageView extends View {
* @see #getImageTintList()
* @see Drawable#setTintList(ColorStateList)
*/
+ @android.view.RemotableViewMethod
public void setImageTintList(@Nullable ColorStateList tint) {
mDrawableTintList = tint;
mHasDrawableTint = true;
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index a44808eb3120..1b76ebf7c8c6 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1308,6 +1308,7 @@ public class ProgressBar extends View {
* @see #getSecondaryProgressTintList()
* @see Drawable#setTintList(ColorStateList)
*/
+ @RemotableViewMethod
public void setSecondaryProgressTintList(@Nullable ColorStateList tint) {
if (mProgressTintInfo == null) {
mProgressTintInfo = new ProgressTintInfo();
@@ -1619,6 +1620,7 @@ public class ProgressBar extends View {
* @param stateDescription The state description.
*/
@Override
+ @RemotableViewMethod
public void setStateDescription(@Nullable CharSequence stateDescription) {
mCustomStateDescription = stateDescription;
if (stateDescription == null) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 30bf546eb83e..e0b4ec71b0a0 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -46,6 +46,8 @@ import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.content.res.loader.ResourcesLoader;
+import android.content.res.loader.ResourcesProvider;
import android.graphics.Bitmap;
import android.graphics.BlendMode;
import android.graphics.Outline;
@@ -62,16 +64,19 @@ import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.Process;
import android.os.StrictMode;
import android.os.UserHandle;
+import android.system.Os;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
+import android.util.SparseIntArray;
import android.util.TypedValue;
import android.util.TypedValue.ComplexDimensionUnit;
import android.view.ContextThemeWrapper;
@@ -92,6 +97,12 @@ import com.android.internal.R;
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.util.Preconditions;
+import java.io.ByteArrayOutputStream;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -224,35 +235,17 @@ public class RemoteViews implements Parcelable, Filter {
})
@Retention(RetentionPolicy.SOURCE)
public @interface MarginType {}
- /**
- * The value will apply to the marginLeft.
- * @hide
- */
+ /** The value will apply to the marginLeft. */
public static final int MARGIN_LEFT = 0;
- /**
- * The value will apply to the marginTop.
- * @hide
- */
+ /** The value will apply to the marginTop. */
public static final int MARGIN_TOP = 1;
- /**
- * The value will apply to the marginRight.
- * @hide
- */
+ /** The value will apply to the marginRight. */
public static final int MARGIN_RIGHT = 2;
- /**
- * The value will apply to the marginBottom.
- * @hide
- */
+ /** The value will apply to the marginBottom. */
public static final int MARGIN_BOTTOM = 3;
- /**
- * The value will apply to the marginStart.
- * @hide
- */
+ /** The value will apply to the marginStart. */
public static final int MARGIN_START = 4;
- /**
- * The value will apply to the marginEnd.
- * @hide
- */
+ /** The value will apply to the marginEnd. */
public static final int MARGIN_END = 5;
/** @hide **/
@@ -538,8 +531,8 @@ public class RemoteViews implements Parcelable, Filter {
* SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!!
*/
private abstract static class Action implements Parcelable {
- public abstract void apply(View root, ViewGroup rootParent,
- InteractionHandler handler) throws ActionException;
+ public abstract void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) throws ActionException;
public static final int MERGE_REPLACE = 0;
public static final int MERGE_APPEND = 1;
@@ -569,8 +562,8 @@ public class RemoteViews implements Parcelable, Filter {
* and return the final action which will run on the UI thread.
* Override this if some of the tasks can be performed async.
*/
- public Action initActionAsync(
- ViewTree root, ViewGroup rootParent, InteractionHandler handler) {
+ public Action initActionAsync(ViewTree root, ViewGroup rootParent,
+ InteractionHandler handler, ColorResources colorResources) {
return this;
}
@@ -613,7 +606,9 @@ public class RemoteViews implements Parcelable, Filter {
// Constant used during async execution. It is not parcelable.
private static final Action ACTION_NOOP = new RuntimeAction() {
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { }
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
+ }
};
/**
@@ -731,7 +726,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final View view = root.findViewById(viewId);
if (!(view instanceof AdapterView<?>)) return;
@@ -766,7 +762,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, final InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, final InteractionHandler handler,
+ ColorResources colorResources) {
final View target = root.findViewById(viewId);
if (target == null) return;
@@ -838,7 +835,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final View target = root.findViewById(viewId);
if (target == null) return;
@@ -861,7 +859,8 @@ public class RemoteViews implements Parcelable, Filter {
if (a instanceof RemoteViewsListAdapter && viewTypeCount <= a.getViewTypeCount()) {
((RemoteViewsListAdapter) a).setViewsList(list);
} else {
- v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount));
+ v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount,
+ colorResources));
}
} else if (target instanceof AdapterViewAnimator) {
AdapterViewAnimator v = (AdapterViewAnimator) target;
@@ -869,7 +868,8 @@ public class RemoteViews implements Parcelable, Filter {
if (a instanceof RemoteViewsListAdapter && viewTypeCount <= a.getViewTypeCount()) {
((RemoteViewsListAdapter) a).setViewsList(list);
} else {
- v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount));
+ v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount,
+ colorResources));
}
}
}
@@ -900,7 +900,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final View target = root.findViewById(viewId);
if (target == null) return;
@@ -937,7 +938,7 @@ public class RemoteViews implements Parcelable, Filter {
@Override
public Action initActionAsync(ViewTree root, ViewGroup rootParent,
- InteractionHandler handler) {
+ InteractionHandler handler, ColorResources colorResources) {
SetRemoteViewsAdapterIntent copy = new SetRemoteViewsAdapterIntent(viewId, intent);
copy.isAsync = true;
return copy;
@@ -976,7 +977,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, final InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, final InteractionHandler handler,
+ ColorResources colorResources) {
final View target = root.findViewById(viewId);
if (target == null) return;
@@ -1055,7 +1057,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, final InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, final InteractionHandler handler,
+ ColorResources colorResources) {
final View target = root.findViewById(viewId);
if (target == null) return;
if (!(target instanceof CompoundButton)) {
@@ -1258,7 +1261,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final View target = root.findViewById(viewId);
if (target == null) return;
@@ -1315,7 +1319,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final View target = root.findViewById(viewId);
if (target == null) return;
@@ -1352,7 +1357,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final View view = root.findViewById(viewId);
if (view == null) return;
@@ -1455,12 +1461,12 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent,
- InteractionHandler handler) throws ActionException {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) throws ActionException {
ReflectionAction ra = new ReflectionAction(viewId, methodName,
BaseReflectionAction.BITMAP,
bitmap);
- ra.apply(root, rootParent, handler);
+ ra.apply(root, rootParent, handler, colorResources);
}
@Override
@@ -1536,7 +1542,8 @@ public class RemoteViews implements Parcelable, Filter {
protected abstract Object getParameterValue(@Nullable View view) throws ActionException;
@Override
- public final void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public final void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final View view = root.findViewById(viewId);
if (view == null) return;
@@ -1554,7 +1561,7 @@ public class RemoteViews implements Parcelable, Filter {
@Override
public final Action initActionAsync(ViewTree root, ViewGroup rootParent,
- InteractionHandler handler) {
+ InteractionHandler handler, ColorResources colorResources) {
final View view = root.findViewById(viewId);
if (view == null) return ACTION_NOOP;
@@ -1956,7 +1963,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
mRunnable.run();
}
}
@@ -2011,7 +2019,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final Context context = root.getContext();
final ViewGroup target = root.findViewById(viewId);
@@ -2020,12 +2029,14 @@ public class RemoteViews implements Parcelable, Filter {
}
// Inflate nested views and add as children
- target.addView(mNestedViews.apply(context, target, handler), mIndex);
+ target.addView(
+ mNestedViews.apply(context, target, handler, null /* size */, colorResources),
+ mIndex);
}
@Override
public Action initActionAsync(ViewTree root, ViewGroup rootParent,
- InteractionHandler handler) {
+ InteractionHandler handler, ColorResources colorResources) {
// In the async implementation, update the view tree so that subsequent calls to
// findViewById return the current view.
root.createTree();
@@ -2037,8 +2048,8 @@ public class RemoteViews implements Parcelable, Filter {
// Inflate nested views and perform all the async tasks for the child remoteView.
final Context context = root.mRoot.getContext();
- final AsyncApplyTask task = mNestedViews.getAsyncApplyTask(
- context, targetVg, null, handler);
+ final AsyncApplyTask task = mNestedViews.getAsyncApplyTask(context, targetVg,
+ null /* listener */, handler, null /* size */, colorResources);
final ViewTree tree = task.doInBackground();
if (tree == null) {
@@ -2051,8 +2062,8 @@ public class RemoteViews implements Parcelable, Filter {
return new RuntimeAction() {
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler)
- throws ActionException {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) throws ActionException {
task.onPostExecute(tree);
targetVg.addView(task.mResult, mIndex);
}
@@ -2113,7 +2124,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final ViewGroup target = root.findViewById(viewId);
if (target == null) {
@@ -2130,7 +2142,7 @@ public class RemoteViews implements Parcelable, Filter {
@Override
public Action initActionAsync(ViewTree root, ViewGroup rootParent,
- InteractionHandler handler) {
+ InteractionHandler handler, ColorResources colorResources) {
// In the async implementation, update the view tree so that subsequent calls to
// findViewById return the current view.
root.createTree();
@@ -2154,8 +2166,8 @@ public class RemoteViews implements Parcelable, Filter {
}
return new RuntimeAction() {
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler)
- throws ActionException {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) throws ActionException {
if (mViewIdToKeep == REMOVE_ALL_VIEWS_ID) {
targetVg.removeAllViews();
return;
@@ -2210,7 +2222,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final View target = root.findViewById(viewId);
if (target == null || target == root) {
@@ -2225,7 +2238,7 @@ public class RemoteViews implements Parcelable, Filter {
@Override
public Action initActionAsync(ViewTree root, ViewGroup rootParent,
- InteractionHandler handler) {
+ InteractionHandler handler, ColorResources colorResources) {
// In the async implementation, update the view tree so that subsequent calls to
// findViewById return the correct view.
root.createTree();
@@ -2244,8 +2257,8 @@ public class RemoteViews implements Parcelable, Filter {
parent.mChildren.remove(target);
return new RuntimeAction() {
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler)
- throws ActionException {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) throws ActionException {
parentVg.removeView(target.mRoot);
}
};
@@ -2324,7 +2337,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final TextView target = root.findViewById(viewId);
if (target == null) return;
if (drawablesLoaded) {
@@ -2355,7 +2369,7 @@ public class RemoteViews implements Parcelable, Filter {
@Override
public Action initActionAsync(ViewTree root, ViewGroup rootParent,
- InteractionHandler handler) {
+ InteractionHandler handler, ColorResources colorResources) {
final TextView target = root.findViewById(viewId);
if (target == null) return ACTION_NOOP;
@@ -2433,7 +2447,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final TextView target = root.findViewById(viewId);
if (target == null) return;
target.setTextSize(units, size);
@@ -2478,7 +2493,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final View target = root.findViewById(viewId);
if (target == null) return;
target.setPadding(left, top, right, bottom);
@@ -2551,7 +2567,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final View target = root.findViewById(viewId);
if (target == null) {
return;
@@ -2664,7 +2681,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final View target = root.findViewById(viewId);
if (target == null) return;
@@ -2699,7 +2717,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
// Let's traverse the viewtree and override all textColors!
Stack<View> viewsToProcess = new Stack<>();
viewsToProcess.add(root);
@@ -2749,7 +2768,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) {
final View target = root.findViewById(mViewId);
if (target == null) return;
@@ -2783,7 +2803,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler)
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources)
throws ActionException {
final View target = root.findViewById(viewId);
if (target == null) return;
@@ -2834,8 +2855,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler)
- throws ActionException {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) throws ActionException {
final View target = root.findViewById(viewId);
if (target == null) return;
@@ -2911,8 +2932,8 @@ public class RemoteViews implements Parcelable, Filter {
}
@Override
- public void apply(View root, ViewGroup rootParent, InteractionHandler handler)
- throws ActionException {
+ public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+ ColorResources colorResources) throws ActionException {
final View target = root.findViewById(viewId);
if (target == null) return;
@@ -4002,7 +4023,6 @@ public class RemoteViews implements Parcelable, Filter {
* @param viewId The id of the view to change
* @param type The margin being set e.g. {@link #MARGIN_END}
* @param dimen a dimension resource to apply to the margin, or 0 to clear the margin.
- * @hide
*/
public void setViewLayoutMarginDimen(@IdRes int viewId, @MarginType int type,
@DimenRes int dimen) {
@@ -4021,7 +4041,6 @@ public class RemoteViews implements Parcelable, Filter {
* @param type The margin being set e.g. {@link #MARGIN_END}
* @param value a value for the margin the given units.
* @param units The unit type of the value e.g. {@link TypedValue#COMPLEX_UNIT_DIP}
- * @hide
*/
public void setViewLayoutMargin(@IdRes int viewId, @MarginType int type, float value,
@ComplexDimensionUnit int units) {
@@ -4039,7 +4058,6 @@ public class RemoteViews implements Parcelable, Filter {
*
* @param width Width of the view in the given units
* @param units The unit type of the value e.g. {@link TypedValue#COMPLEX_UNIT_DIP}
- * @hide
*/
public void setViewLayoutWidth(@IdRes int viewId, float width,
@ComplexDimensionUnit int units) {
@@ -4051,7 +4069,6 @@ public class RemoteViews implements Parcelable, Filter {
* the result of {@link Resources#getDimensionPixelSize(int)}.
*
* @param widthDimen the dimension resource for the view's width
- * @hide
*/
public void setViewLayoutWidthDimen(@IdRes int viewId, @DimenRes int widthDimen) {
addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_WIDTH, widthDimen));
@@ -4068,7 +4085,6 @@ public class RemoteViews implements Parcelable, Filter {
*
* @param height height of the view in the given units
* @param units The unit type of the value e.g. {@link TypedValue#COMPLEX_UNIT_DIP}
- * @hide
*/
public void setViewLayoutHeight(@IdRes int viewId, float height,
@ComplexDimensionUnit int units) {
@@ -4080,7 +4096,6 @@ public class RemoteViews implements Parcelable, Filter {
* the result of {@link Resources#getDimensionPixelSize(int)}.
*
* @param heightDimen a dimen resource to read the height from.
- * @hide
*/
public void setViewLayoutHeightDimen(@IdRes int viewId, @DimenRes int heightDimen) {
addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_HEIGHT, heightDimen));
@@ -4231,10 +4246,9 @@ public class RemoteViews implements Parcelable, Filter {
* @param viewId The id of the view on which to call the method.
* @param methodName The name of the method to call.
* @param value The value to pass to the method.
- *
- * @hide
*/
- public void setColorStateList(@IdRes int viewId, String methodName, ColorStateList value) {
+ public void setColorStateList(@IdRes int viewId, @NonNull String methodName,
+ @Nullable ColorStateList value) {
addAction(new ReflectionAction(viewId, methodName, BaseReflectionAction.COLOR_STATE_LIST,
value));
}
@@ -4687,7 +4701,7 @@ public class RemoteViews implements Parcelable, Filter {
RemoteViews rvToApply = getRemoteViewsToApply(context, size);
View result = inflateView(context, rvToApply, parent);
- rvToApply.performApply(result, parent, handler);
+ rvToApply.performApply(result, parent, handler, null);
return result;
}
@@ -4699,27 +4713,39 @@ public class RemoteViews implements Parcelable, Filter {
/** @hide */
public View applyWithTheme(@NonNull Context context, @NonNull ViewGroup parent,
- @Nullable InteractionHandler handler,
- @StyleRes int applyThemeResId,
+ @Nullable InteractionHandler handler, @StyleRes int applyThemeResId,
@Nullable PointF size) {
RemoteViews rvToApply = getRemoteViewsToApply(context, size);
- View result = inflateView(context, rvToApply, parent, applyThemeResId);
- rvToApply.performApply(result, parent, handler);
+ View result = inflateView(context, rvToApply, parent, applyThemeResId, null);
+ rvToApply.performApply(result, parent, handler, null);
+ return result;
+ }
+
+ /** @hide */
+ public View apply(Context context, ViewGroup parent, InteractionHandler handler,
+ @NonNull PointF size, @Nullable ColorResources colorResources) {
+ RemoteViews rvToApply = getRemoteViewsToApply(context, size);
+
+ View result = inflateView(context, rvToApply, parent, 0, colorResources);
+ rvToApply.performApply(result, parent, handler, colorResources);
return result;
}
private View inflateView(Context context, RemoteViews rv, ViewGroup parent) {
- return inflateView(context, rv, parent, 0);
+ return inflateView(context, rv, parent, 0, null);
}
private View inflateView(Context context, RemoteViews rv, ViewGroup parent,
- @StyleRes int applyThemeResId) {
+ @StyleRes int applyThemeResId, @Nullable ColorResources colorResources) {
// RemoteViews may be built by an application installed in another
// user. So build a context that loads resources from that user but
// still returns the current users userId so settings like data / time formats
// are loaded without requiring cross user persmissions.
final Context contextForResources = getContextForResources(context);
+ if (colorResources != null) {
+ colorResources.apply(contextForResources);
+ }
Context inflationContext = new RemoteViewsContextWrapper(context, contextForResources);
// If mApplyThemeResId is not given, Theme.DeviceDefault will be used.
@@ -4781,34 +4807,37 @@ public class RemoteViews implements Parcelable, Filter {
*/
public CancellationSignal applyAsync(
Context context, ViewGroup parent, Executor executor, OnViewAppliedListener listener) {
- return applyAsync(context, parent, executor, listener, null);
+ return applyAsync(context, parent, executor, listener, null /* handler */);
}
/** @hide */
public CancellationSignal applyAsync(Context context, ViewGroup parent,
Executor executor, OnViewAppliedListener listener, InteractionHandler handler) {
- return applyAsync(context, parent, executor, listener, handler, null);
+ return applyAsync(context, parent, executor, listener, handler, null /* size */);
}
/** @hide */
public CancellationSignal applyAsync(Context context, ViewGroup parent,
Executor executor, OnViewAppliedListener listener, InteractionHandler handler,
PointF size) {
- return getAsyncApplyTask(context, parent, listener, handler, size).startTaskOnExecutor(
- executor);
+ return getAsyncApplyTask(context, parent, listener, handler, size, null /* themeColors */)
+ .startTaskOnExecutor(executor);
}
- private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent,
- OnViewAppliedListener listener, InteractionHandler handler) {
- return getAsyncApplyTask(context, parent, listener, handler, null);
+ /** @hide */
+ public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor,
+ OnViewAppliedListener listener, InteractionHandler handler, PointF size,
+ ColorResources colorResources) {
+ return getAsyncApplyTask(context, parent, listener, handler, size, colorResources)
+ .startTaskOnExecutor(executor);
}
private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent,
- OnViewAppliedListener listener, InteractionHandler handler, PointF size) {
- return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context,
- listener,
- handler, null);
+ OnViewAppliedListener listener, InteractionHandler handler, PointF size,
+ ColorResources colorResources) {
+ return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context, listener,
+ handler, colorResources, null /* result */);
}
private class AsyncApplyTask extends AsyncTask<Void, Void, ViewTree>
@@ -4819,6 +4848,7 @@ public class RemoteViews implements Parcelable, Filter {
final Context mContext;
final OnViewAppliedListener mListener;
final InteractionHandler mHandler;
+ final ColorResources mColorResources;
private View mResult;
private ViewTree mTree;
@@ -4827,11 +4857,12 @@ public class RemoteViews implements Parcelable, Filter {
private AsyncApplyTask(
RemoteViews rv, ViewGroup parent, Context context, OnViewAppliedListener listener,
- InteractionHandler handler, View result) {
+ InteractionHandler handler, ColorResources colorResources, View result) {
mRV = rv;
mParent = parent;
mContext = context;
mListener = listener;
+ mColorResources = colorResources;
mHandler = handler;
mResult = result;
@@ -4841,7 +4872,7 @@ public class RemoteViews implements Parcelable, Filter {
protected ViewTree doInBackground(Void... params) {
try {
if (mResult == null) {
- mResult = inflateView(mContext, mRV, mParent);
+ mResult = inflateView(mContext, mRV, mParent, 0, mColorResources);
}
mTree = new ViewTree(mResult);
@@ -4850,7 +4881,8 @@ public class RemoteViews implements Parcelable, Filter {
mActions = new Action[count];
for (int i = 0; i < count && !isCancelled(); i++) {
// TODO: check if isCancelled in nested views.
- mActions[i] = mRV.mActions.get(i).initActionAsync(mTree, mParent, mHandler);
+ mActions[i] = mRV.mActions.get(i).initActionAsync(mTree, mParent, mHandler,
+ mColorResources);
}
} else {
mActions = null;
@@ -4875,7 +4907,7 @@ public class RemoteViews implements Parcelable, Filter {
InteractionHandler handler = mHandler == null
? DEFAULT_INTERACTION_HANDLER : mHandler;
for (Action a : mActions) {
- a.apply(viewTree.mRoot, mParent, handler);
+ a.apply(viewTree.mRoot, mParent, handler, mColorResources);
}
}
} catch (Exception e) {
@@ -4919,16 +4951,17 @@ public class RemoteViews implements Parcelable, Filter {
* the {@link #apply(Context,ViewGroup)} call.
*/
public void reapply(Context context, View v) {
- reapply(context, v, null, null);
+ reapply(context, v, null /* handler */);
}
/** @hide */
public void reapply(Context context, View v, InteractionHandler handler) {
- reapply(context, v, handler, null);
+ reapply(context, v, handler, null /* size */, null /* colorResources */);
}
/** @hide */
- public void reapply(Context context, View v, InteractionHandler handler, PointF size) {
+ public void reapply(Context context, View v, InteractionHandler handler, PointF size,
+ ColorResources colorResources) {
RemoteViews rvToApply = getRemoteViewsToApply(context, size);
// In the case that a view has this RemoteViews applied in one orientation or size, is
@@ -4942,7 +4975,7 @@ public class RemoteViews implements Parcelable, Filter {
}
}
- rvToApply.performApply(v, (ViewGroup) v.getParent(), handler);
+ rvToApply.performApply(v, (ViewGroup) v.getParent(), handler, colorResources);
}
/**
@@ -4958,20 +4991,21 @@ public class RemoteViews implements Parcelable, Filter {
* @return CancellationSignal
* @hide
*/
- public CancellationSignal reapplyAsync(
- Context context, View v, Executor executor, OnViewAppliedListener listener) {
- return reapplyAsync(context, v, executor, listener, null, null);
+ public CancellationSignal reapplyAsync(Context context, View v, Executor executor,
+ OnViewAppliedListener listener) {
+ return reapplyAsync(context, v, executor, listener, null);
}
/** @hide */
public CancellationSignal reapplyAsync(Context context, View v, Executor executor,
OnViewAppliedListener listener, InteractionHandler handler) {
- return reapplyAsync(context, v, executor, listener, handler, null);
+ return reapplyAsync(context, v, executor, listener, handler, null, null);
}
/** @hide */
public CancellationSignal reapplyAsync(Context context, View v, Executor executor,
- OnViewAppliedListener listener, InteractionHandler handler, PointF size) {
+ OnViewAppliedListener listener, InteractionHandler handler, PointF size,
+ ColorResources colorResources) {
RemoteViews rvToApply = getRemoteViewsToApply(context, size);
// In the case that a view has this RemoteViews applied in one orientation, is persisted
@@ -4985,16 +5019,18 @@ public class RemoteViews implements Parcelable, Filter {
}
return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
- context, listener, handler, v).startTaskOnExecutor(executor);
+ context, listener, handler, colorResources, v).startTaskOnExecutor(
+ executor);
}
- private void performApply(View v, ViewGroup parent, InteractionHandler handler) {
+ private void performApply(View v, ViewGroup parent, InteractionHandler handler,
+ ColorResources colorResources) {
if (mActions != null) {
handler = handler == null ? DEFAULT_INTERACTION_HANDLER : handler;
final int count = mActions.size();
for (int i = 0; i < count; i++) {
Action a = mActions.get(i);
- a.apply(v, parent, handler);
+ a.apply(v, parent, handler, colorResources);
}
}
}
@@ -5035,6 +5071,122 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
+ * Object allowing the modification of a context to overload the system's dynamic colors.
+ *
+ * Only colors from {@link android.R.color#system_primary_0} to
+ * {@link android.R.color#system_neutral_1000} can be overloaded.
+ * @hide
+ */
+ public static final class ColorResources {
+ // Set of valid colors resources.
+ private static final int FIRST_RESOURCE_COLOR_ID = android.R.color.system_primary_0;
+ private static final int LAST_RESOURCE_COLOR_ID = android.R.color.system_neutral_1000;
+ // Size, in bytes, of an entry in the array of colors in an ARSC file.
+ private static final int ARSC_ENTRY_SIZE = 16;
+
+ private ResourcesLoader mLoader;
+
+ private ColorResources(ResourcesLoader loader) {
+ mLoader = loader;
+ }
+
+ /**
+ * Apply the color resources to the given context.
+ *
+ * No resource resolution must have be done on the context given to that method.
+ */
+ public void apply(Context context) {
+ context.getResources().addLoaders(mLoader);
+ }
+
+ private static ByteArrayOutputStream readFileContent(InputStream input) throws IOException {
+ ByteArrayOutputStream content = new ByteArrayOutputStream(2048);
+ byte[] buffer = new byte[4096];
+ while (input.available() > 0) {
+ int read = input.read(buffer);
+ content.write(buffer, 0, read);
+ }
+ return content;
+ }
+
+ /**
+ * Creates the compiled resources content from the asset stored in the APK.
+ *
+ * The asset is a compiled resource with the correct resources name and correct ids, only
+ * the values are incorrect. The last value is at the very end of the file. The resources
+ * are in an array, the array's entries are 16 bytes each. We use this to work out the
+ * location of all the positions of the various resources.
+ */
+ private static byte[] createCompiledResourcesContent(Context context,
+ SparseIntArray colorResources) throws IOException {
+ byte[] content;
+ try (InputStream input = context.getResources().openRawResource(
+ com.android.internal.R.raw.remote_views_color_resources)) {
+ ByteArrayOutputStream rawContent = readFileContent(input);
+ content = rawContent.toByteArray();
+ }
+ int valuesOffset =
+ content.length - (LAST_RESOURCE_COLOR_ID & 0xffff) * ARSC_ENTRY_SIZE - 4;
+ if (valuesOffset < 0) {
+ Log.e(LOG_TAG, "ARSC file for theme colors is invalid.");
+ return null;
+ }
+ for (int colorRes = FIRST_RESOURCE_COLOR_ID; colorRes <= LAST_RESOURCE_COLOR_ID;
+ colorRes++) {
+ // The last 2 bytes are the index in the color array.
+ int index = colorRes & 0xffff;
+ int offset = valuesOffset + index * ARSC_ENTRY_SIZE;
+ int value = colorResources.get(colorRes, context.getColor(colorRes));
+ // Write the 32 bit integer in little endian
+ for (int b = 0; b < 4; b++) {
+ content[offset + b] = (byte) (value & 0xff);
+ value >>= 8;
+ }
+ }
+ return content;
+ }
+
+ /**
+ * Adds a resource loader for theme colors to the given context.
+ *
+ * @param context Context of the view hosting the widget.
+ * @param colorMapping Mapping of resources to color values.
+ *
+ * @hide
+ */
+ public static ColorResources create(Context context, SparseIntArray colorMapping) {
+ try {
+ byte[] contentBytes = createCompiledResourcesContent(context, colorMapping);
+ if (contentBytes == null) {
+ return null;
+ }
+ FileDescriptor arscFile = null;
+ try {
+ arscFile = Os.memfd_create("remote_views_theme_colors.arsc", 0 /* flags */);
+ // Note: This must not be closed through the OutputStream.
+ try (OutputStream pipeWriter = new FileOutputStream(arscFile)) {
+ pipeWriter.write(contentBytes);
+
+ try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(arscFile)) {
+ ResourcesLoader colorsLoader = new ResourcesLoader();
+ colorsLoader.addProvider(ResourcesProvider
+ .loadFromTable(pfd, null /* assetsProvider */));
+ return new ColorResources(colorsLoader);
+ }
+ }
+ } finally {
+ if (arscFile != null) {
+ Os.close(arscFile);
+ }
+ }
+ } catch (Exception ex) {
+ Log.e(LOG_TAG, "Failed to setup the context for theme colors", ex);
+ }
+ return null;
+ }
+ }
+
+ /**
* Returns the number of actions in this RemoteViews. Can be used as a sequence number.
*
* @hide
diff --git a/core/java/android/widget/RemoteViewsListAdapter.java b/core/java/android/widget/RemoteViewsListAdapter.java
index b80fe4871616..827d03317d6a 100644
--- a/core/java/android/widget/RemoteViewsListAdapter.java
+++ b/core/java/android/widget/RemoteViewsListAdapter.java
@@ -31,12 +31,14 @@ public class RemoteViewsListAdapter extends BaseAdapter {
private ArrayList<RemoteViews> mRemoteViewsList;
private ArrayList<Integer> mViewTypes = new ArrayList<Integer>();
private int mViewTypeCount;
+ private RemoteViews.ColorResources mColorResources;
public RemoteViewsListAdapter(Context context, ArrayList<RemoteViews> remoteViews,
- int viewTypeCount) {
+ int viewTypeCount, RemoteViews.ColorResources colorResources) {
mContext = context;
mRemoteViewsList = remoteViews;
mViewTypeCount = viewTypeCount;
+ mColorResources = colorResources;
init();
}
@@ -90,9 +92,10 @@ public class RemoteViewsListAdapter extends BaseAdapter {
if (convertView != null && rv != null &&
convertView.getId() == rv.getLayoutId()) {
v = convertView;
- rv.reapply(mContext, v);
+ rv.reapply(mContext, v, null /* handler */, null /* size */, mColorResources);
} else {
- v = rv.apply(mContext, parent);
+ v = rv.apply(mContext, parent, null /* handler */, null /* size */,
+ mColorResources);
}
return v;
} else {
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 64d09de49f2d..65f3da79afe0 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -335,6 +335,27 @@ public class ScrollView extends FrameLayout {
}
/**
+ * Returns the {@link EdgeEffect#getType()} for the edge effects.
+ * @return the {@link EdgeEffect#getType()} for the edge effects.
+ * @attr ref android.R.styleable#EdgeEffect_edgeEffectType
+ */
+ @EdgeEffect.EdgeEffectType
+ public int getEdgeEffectType() {
+ return mEdgeGlowTop.getType();
+ }
+
+ /**
+ * Sets the {@link EdgeEffect#setType(int)} for the edge effects.
+ * @param type The edge effect type to use for the edge effects.
+ * @attr ref android.R.styleable#EdgeEffect_edgeEffectType
+ */
+ public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) {
+ mEdgeGlowTop.setType(type);
+ mEdgeGlowBottom.setType(type);
+ invalidate();
+ }
+
+ /**
* @return The maximum amount this scroll view will scroll in response to
* an arrow event.
*/
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 0f2089a5463f..ca0747fadf14 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4756,6 +4756,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @see #getJustificationMode()
*/
@Layout.JustificationMode
+ @android.view.RemotableViewMethod
public void setJustificationMode(@Layout.JustificationMode int justificationMode) {
mJustificationMode = justificationMode;
if (mLayout != null) {
@@ -5232,6 +5233,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @see android.view.Gravity
* @attr ref android.R.styleable#TextView_gravity
*/
+ @android.view.RemotableViewMethod
public void setGravity(int gravity) {
if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
gravity |= Gravity.START;
@@ -5826,6 +5828,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_lineHeight
*/
+ @android.view.RemotableViewMethod
public void setLineHeight(@Px @IntRange(from = 0) int lineHeight) {
Preconditions.checkArgumentNonnegative(lineHeight);
@@ -10277,6 +10280,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @see #setTransformationMethod(TransformationMethod)
* @attr ref android.R.styleable#TextView_textAllCaps
*/
+ @android.view.RemotableViewMethod
public void setAllCaps(boolean allCaps) {
if (allCaps) {
setTransformationMethod(new AllCapsTransformationMethod(getContext()));
diff --git a/core/java/android/widget/ToastPresenter.java b/core/java/android/widget/ToastPresenter.java
index 2904a8c889a2..0f2a3ca6936b 100644
--- a/core/java/android/widget/ToastPresenter.java
+++ b/core/java/android/widget/ToastPresenter.java
@@ -184,7 +184,7 @@ public class ToastPresenter {
mParams.y = yOffset;
mParams.horizontalMargin = horizontalMargin;
mParams.verticalMargin = verticalMargin;
- addToastView();
+ mView.setLayoutParams(mParams);
}
/**
diff --git a/core/java/com/android/internal/graphics/palette/CelebiQuantizer.java b/core/java/com/android/internal/graphics/palette/CelebiQuantizer.java
new file mode 100644
index 000000000000..de6bf2044dbc
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/CelebiQuantizer.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.graphics.palette;
+
+import java.util.List;
+
+/**
+ * An implementation of Celebi's WSM quantizer, or, a Kmeans quantizer that starts with centroids
+ * from a Wu quantizer to ensure 100% reproducible and quality results, and has some optimizations
+ * to the Kmeans algorithm.
+ *
+ * See Celebi 2011, “Improving the Performance of K-Means for Color Quantization”
+ */
+public class CelebiQuantizer implements Quantizer {
+ private List<Palette.Swatch> mSwatches;
+
+ public CelebiQuantizer() { }
+
+ @Override
+ public void quantize(int[] pixels, int maxColors) {
+ WuQuantizer wu = new WuQuantizer(pixels, maxColors);
+ wu.quantize(pixels, maxColors);
+ List<Palette.Swatch> wuSwatches = wu.getQuantizedColors();
+ LABCentroid labCentroidProvider = new LABCentroid();
+ WSMeansQuantizer kmeans =
+ new WSMeansQuantizer(WSMeansQuantizer.createStartingCentroids(labCentroidProvider,
+ wuSwatches), labCentroidProvider, pixels, maxColors);
+ kmeans.quantize(pixels, maxColors);
+ mSwatches = kmeans.getQuantizedColors();
+ }
+
+ @Override
+ public List<Palette.Swatch> getQuantizedColors() {
+ return mSwatches;
+ }
+}
diff --git a/core/java/android/uwb/AngleOfArrivalSupport.aidl b/core/java/com/android/internal/graphics/palette/CentroidProvider.java
index 57666ff8bca9..5fcfcbab3159 100644
--- a/core/java/android/uwb/AngleOfArrivalSupport.aidl
+++ b/core/java/com/android/internal/graphics/palette/CentroidProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,31 +14,25 @@
* limitations under the License.
*/
-package android.uwb;
+package com.android.internal.graphics.palette;
-/**
- * @hide
- */
-@Backing(type="int")
-enum AngleOfArrivalSupport {
- /**
- * The device does not support angle of arrival
- */
- NONE,
+import android.annotation.ColorInt;
- /**
- * The device supports planar angle of arrival
- */
- TWO_DIMENSIONAL,
+interface CentroidProvider {
+ /**
+ * @return 3 dimensions representing the color
+ */
+ float[] getCentroid(@ColorInt int color);
- /**
- * The device does supports three dimensional angle of arrival with hemispherical azimuth angles
- */
- THREE_DIMENSIONAL_HEMISPHERICAL,
+ /**
+ * @param centroid 3 dimensions representing the color
+ * @return 32-bit ARGB representation
+ */
+ @ColorInt
+ int getColor(float[] centroid);
- /**
- * The device does supports three dimensional angle of arrival with full azimuth angles
- */
- THREE_DIMENSIONAL_SPHERICAL,
+ /**
+ * Distance between two centroids.
+ */
+ float distance(float[] a, float[] b);
}
-
diff --git a/core/java/com/android/internal/graphics/palette/ColorCutQuantizer.java b/core/java/com/android/internal/graphics/palette/ColorCutQuantizer.java
index 9ac753b6d6ce..777949434c36 100644
--- a/core/java/com/android/internal/graphics/palette/ColorCutQuantizer.java
+++ b/core/java/com/android/internal/graphics/palette/ColorCutQuantizer.java
@@ -35,6 +35,8 @@ package com.android.internal.graphics.palette;
import android.graphics.Color;
import android.util.TimingLogger;
+import com.android.internal.graphics.palette.Palette.Swatch;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -42,9 +44,6 @@ import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
-import com.android.internal.graphics.ColorUtils;
-import com.android.internal.graphics.palette.Palette.Swatch;
-
/**
* Copied from: frameworks/support/v7/palette/src/main/java/android/support/v7/
* graphics/ColorCutQuantizer.java
@@ -77,20 +76,17 @@ final class ColorCutQuantizer implements Quantizer {
int[] mHistogram;
List<Swatch> mQuantizedColors;
TimingLogger mTimingLogger;
- Palette.Filter[] mFilters;
private final float[] mTempHsl = new float[3];
/**
* Execute color quantization.
*
- * @param pixels histogram representing an image's pixel data
+ * @param pixels histogram representing an image's pixel data
* @param maxColors The maximum number of colors that should be in the result palette.
- * @param filters Set of filters to use in the quantization stage
*/
- public void quantize(final int[] pixels, final int maxColors, final Palette.Filter[] filters) {
+ public void quantize(final int[] pixels, final int maxColors) {
mTimingLogger = LOG_TIMINGS ? new TimingLogger(LOG_TAG, "Creation") : null;
- mFilters = filters;
final int[] hist = mHistogram = new int[1 << (QUANTIZE_WORD_WIDTH * 3)];
for (int i = 0; i < pixels.length; i++) {
@@ -108,10 +104,6 @@ final class ColorCutQuantizer implements Quantizer {
// Now let's count the number of distinct colors
int distinctColorCount = 0;
for (int color = 0; color < hist.length; color++) {
- if (hist[color] > 0 && shouldIgnoreColor(color)) {
- // If we should ignore the color, set the population to 0
- hist[color] = 0;
- }
if (hist[color] > 0) {
// If the color has population, increase the distinct color count
distinctColorCount++;
@@ -186,7 +178,7 @@ final class ColorCutQuantizer implements Quantizer {
* and splitting them. Once split, the new box and the remaining box are offered back to the
* queue.
*
- * @param queue {@link java.util.PriorityQueue} to poll for boxes
+ * @param queue {@link java.util.PriorityQueue} to poll for boxes
* @param maxSize Maximum amount of boxes to split
*/
private void splitBoxes(final PriorityQueue<Vbox> queue, final int maxSize) {
@@ -216,11 +208,7 @@ final class ColorCutQuantizer implements Quantizer {
ArrayList<Swatch> colors = new ArrayList<>(vboxes.size());
for (Vbox vbox : vboxes) {
Swatch swatch = vbox.getAverageColor();
- if (!shouldIgnoreColor(swatch)) {
- // As we're averaging a color box, we can still get colors which we do not want, so
- // we check again here
- colors.add(swatch);
- }
+ colors.add(swatch);
}
return colors;
}
@@ -230,7 +218,7 @@ final class ColorCutQuantizer implements Quantizer {
*/
private class Vbox {
// lower and upper index are inclusive
- private int mLowerIndex;
+ private final int mLowerIndex;
private int mUpperIndex;
// Population of colors within this box
private int mPopulation;
@@ -373,7 +361,7 @@ final class ColorCutQuantizer implements Quantizer {
modifySignificantOctet(colors, longestDimension, mLowerIndex, mUpperIndex);
final int midPoint = mPopulation / 2;
- for (int i = mLowerIndex, count = 0; i <= mUpperIndex; i++) {
+ for (int i = mLowerIndex, count = 0; i <= mUpperIndex; i++) {
count += hist[colors[i]];
if (count >= midPoint) {
// we never want to split on the upperIndex, as this will result in the same
@@ -447,27 +435,6 @@ final class ColorCutQuantizer implements Quantizer {
}
}
- private boolean shouldIgnoreColor(int color565) {
- final int rgb = approximateToRgb888(color565);
- ColorUtils.colorToHSL(rgb, mTempHsl);
- return shouldIgnoreColor(rgb, mTempHsl);
- }
-
- private boolean shouldIgnoreColor(Swatch color) {
- return shouldIgnoreColor(color.getRgb(), color.getHsl());
- }
-
- private boolean shouldIgnoreColor(int rgb, float[] hsl) {
- if (mFilters != null && mFilters.length > 0) {
- for (int i = 0, count = mFilters.length; i < count; i++) {
- if (!mFilters[i].isAllowed(rgb, hsl)) {
- return true;
- }
- }
- }
- return false;
- }
-
/**
* Comparator which sorts {@link Vbox} instances based on their volume, in descending order
*/
@@ -498,7 +465,8 @@ final class ColorCutQuantizer implements Quantizer {
}
private static int approximateToRgb888(int color) {
- return approximateToRgb888(quantizedRed(color), quantizedGreen(color), quantizedBlue(color));
+ return approximateToRgb888(quantizedRed(color), quantizedGreen(color),
+ quantizedBlue(color));
}
/**
diff --git a/core/java/com/android/internal/graphics/palette/Contrast.java b/core/java/com/android/internal/graphics/palette/Contrast.java
new file mode 100644
index 000000000000..3dd1b8d8117c
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/Contrast.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.graphics.palette;
+
+/**
+ * Helper methods for determining contrast between two colors, either via the colors themselves
+ * or components in different color spaces.
+ */
+public class Contrast {
+ /**
+ *
+ * @param y Y in XYZ that contrasts with the returned Y value
+ * @param contrast contrast ratio between color argument and returned Y value. Must be >= 1
+ * or an exception will be thrown
+ * @return the lower Y coordinate in XYZ space that contrasts with color, or -1 if reaching
+ * no Y coordinate reaches contrast with color.
+ */
+ public static float lighterY(float y, float contrast) {
+ assert (contrast >= 1);
+ float answer = -5 + contrast * (5 + y);
+ if (answer > 100.0) {
+ return -1;
+ }
+ return answer;
+ }
+
+
+ /**
+ * @param y Y in XYZ that contrasts with the returned Y value
+ * @param contrast contrast ratio between color argument and returned Y value. Must be >= 1
+ * or an exception will be thrown
+ * @return the lower Y coordinate in XYZ space that contrasts with color, or -1 if reaching
+ * no Y coordinate reaches contrast with color.
+ */
+ public static float darkerY(float y, float contrast) {
+ assert (contrast >= 1);
+ float answer = (5 - 5 * contrast + y) / contrast;
+ if (answer < 0.0) {
+ return -1;
+ }
+ return answer;
+ }
+
+ /**
+ * Convert L* in L*a*b* to Y in XYZ.
+ *
+ * @param lstar L* in L*a*b*
+ * @return Y in XYZ
+ */
+ public static float lstarToY(float lstar) {
+ // http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
+ float ke = 8.0f;
+ if (lstar > ke) {
+ return (float) (Math.pow(((lstar + 16.0) / 116.0), 3) * 100.0);
+ } else {
+ return (float) (lstar / (24389 / 27) * 100.0);
+ }
+ }
+
+ /**
+ * Convert Y in XYZ to L* in L*a*b*.
+ *
+ * @param y Y in XYZ
+ * @return L* in L*a*b*
+ */
+ public static float yToLstar(float y) {
+ y = y / 100.0f;
+ float e = 216.0f / 24389.0f;
+ float y_intermediate;
+ if (y <= e) {
+ y_intermediate = (24389.f / 27.f) * y;
+ // If y < e, can skip consecutive steps of / 116 + 16 followed by * 116 - 16.
+ return y_intermediate;
+ } else {
+ y_intermediate = (float) Math.cbrt(y);
+ }
+ return 116.f * y_intermediate - 16.f;
+ }
+
+
+ /**
+ * @return Contrast ratio between two Y values in XYZ space.
+ */
+ public static float contrastYs(float y1, float y2) {
+ final float lighter = Math.max(y1, y2);
+ final float darker = (lighter == y1) ? y2 : y1;
+ return (lighter + 5) / (darker + 5);
+ }
+}
diff --git a/core/java/com/android/internal/graphics/palette/LABCentroid.java b/core/java/com/android/internal/graphics/palette/LABCentroid.java
new file mode 100644
index 000000000000..98d5d2684857
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/LABCentroid.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.graphics.palette;
+
+import android.graphics.Color;
+import android.graphics.ColorSpace;
+
+/**
+ * Allows quantizers to operate in the L*a*b* colorspace.
+ * L*a*b* is a good choice for measuring distance between colors.
+ * Better spaces, and better distance calculations even in L*a*b* exist, but measuring distance
+ * in L*a*b* space, also known as deltaE, is a universally accepted standard across industries
+ * and worldwide.
+ */
+public class LABCentroid implements CentroidProvider {
+ final ColorSpace.Connector mRgbToLab;
+ final ColorSpace.Connector mLabToRgb;
+
+ public LABCentroid() {
+ mRgbToLab = ColorSpace.connect(
+ ColorSpace.get(ColorSpace.Named.SRGB),
+ ColorSpace.get(ColorSpace.Named.CIE_LAB));
+ mLabToRgb = ColorSpace.connect(ColorSpace.get(ColorSpace.Named.CIE_LAB),
+ ColorSpace.get(ColorSpace.Named.SRGB));
+ }
+
+ @Override
+ public float[] getCentroid(int color) {
+ float r = Color.red(color) / 255.f;
+ float g = Color.green(color) / 255.f;
+ float b = Color.blue(color) / 255.f;
+
+ float[] transform = mRgbToLab.transform(r, g, b);
+ return transform;
+ }
+
+ @Override
+ public int getColor(float[] centroid) {
+ float[] rgb = mLabToRgb.transform(centroid);
+ int color = Color.rgb(rgb[0], rgb[1], rgb[2]);
+ return color;
+ }
+
+ @Override
+ public float distance(float[] a, float[] b) {
+ // Standard v1 CIELAB deltaE formula, 1976 - easily improved upon, however,
+ // improvements do not significantly impact the Palette algorithm's results.
+ double dL = a[0] - b[0];
+ double dA = a[1] - b[1];
+ double dB = a[2] - b[2];
+ return (float) (Math.pow(dL, 2) + Math.pow(dA, 2) + Math.pow(dB, 2));
+ }
+}
diff --git a/core/java/com/android/internal/graphics/palette/Mean.java b/core/java/com/android/internal/graphics/palette/Mean.java
new file mode 100644
index 000000000000..894f91b6261c
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/Mean.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.graphics.palette;
+
+import java.util.Random;
+
+/**
+ * Represents a centroid in Kmeans algorithms.
+ */
+public class Mean {
+ private static final Random RANDOM = new Random(0);
+
+ public float[] center;
+
+ /**
+ * Constructor.
+ *
+ * @param upperBound maximum value of a dimension in the space Kmeans is optimizing in
+ */
+ Mean(int upperBound) {
+ center =
+ new float[]{
+ RANDOM.nextInt(upperBound + 1), RANDOM.nextInt(upperBound + 1),
+ RANDOM.nextInt(upperBound + 1)
+ };
+ }
+
+ Mean(float[] center) {
+ this.center = center;
+ }
+}
diff --git a/core/java/com/android/internal/graphics/palette/MeanBucket.java b/core/java/com/android/internal/graphics/palette/MeanBucket.java
new file mode 100644
index 000000000000..ae8858a8107c
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/MeanBucket.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.graphics.palette;
+
+import java.util.HashSet;
+import java.util.Set;
+
+class MeanBucket {
+ float[] mTotal = {0.f, 0.f, 0.f};
+ int mCount = 0;
+ Set<Integer> mColors = new HashSet<>();
+
+ void add(float[] colorAsDoubles, int color, int colorCount) {
+ assert (colorAsDoubles.length == 3);
+ mColors.add(color);
+ mTotal[0] += (colorAsDoubles[0] * colorCount);
+ mTotal[1] += (colorAsDoubles[1] * colorCount);
+ mTotal[2] += (colorAsDoubles[2] * colorCount);
+ mCount += colorCount;
+ }
+
+ float[] getCentroid() {
+ if (mCount == 0) {
+ return null;
+ }
+ return new float[]{mTotal[0] / mCount, mTotal[1] / mCount, mTotal[2] / mCount};
+ }
+}
diff --git a/core/java/com/android/internal/graphics/palette/Palette.java b/core/java/com/android/internal/graphics/palette/Palette.java
index a4f9a596050c..8b1137d7de7c 100644
--- a/core/java/com/android/internal/graphics/palette/Palette.java
+++ b/core/java/com/android/internal/graphics/palette/Palette.java
@@ -19,48 +19,24 @@ package com.android.internal.graphics.palette;
import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.Px;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
-import android.os.AsyncTask;
-import android.util.ArrayMap;
import android.util.Log;
-import android.util.SparseBooleanArray;
-import android.util.TimingLogger;
-import com.android.internal.graphics.ColorUtils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
/**
- * Copied from: /frameworks/support/v7/palette/src/main/java/android/support/v7/
- * graphics/Palette.java
- *
* A helper class to extract prominent colors from an image.
- * <p>
- * A number of colors with different profiles are extracted from the image:
- * <ul>
- * <li>Vibrant</li>
- * <li>Vibrant Dark</li>
- * <li>Vibrant Light</li>
- * <li>Muted</li>
- * <li>Muted Dark</li>
- * <li>Muted Light</li>
- * </ul>
- * These can be retrieved from the appropriate getter method.
*
- * <p>
- * Instances are created with a {@link Palette.Builder} which supports several options to tweak the
+ * <p>Instances are created with a {@link Builder} which supports several options to tweak the
* generated Palette. See that class' documentation for more information.
- * <p>
- * Generation should always be completed on a background thread, ideally the one in
- * which you load your image on. {@link Palette.Builder} supports both synchronous and asynchronous
- * generation:
+ *
+ * <p>Generation should always be completed on a background thread, ideally the one in which you
+ * load your image on. {@link Builder} supports both synchronous and asynchronous generation:
*
* <pre>
* // Synchronous
@@ -85,346 +61,59 @@ public final class Palette {
/**
* Called when the {@link Palette} has been generated.
*/
- void onGenerated(Palette palette);
+ void onGenerated(@Nullable Palette palette);
}
static final int DEFAULT_RESIZE_BITMAP_AREA = 112 * 112;
static final int DEFAULT_CALCULATE_NUMBER_COLORS = 16;
-
- static final float MIN_CONTRAST_TITLE_TEXT = 3.0f;
- static final float MIN_CONTRAST_BODY_TEXT = 4.5f;
-
static final String LOG_TAG = "Palette";
- static final boolean LOG_TIMINGS = false;
- /**
- * Start generating a {@link Palette} with the returned {@link Palette.Builder} instance.
- */
- public static Palette.Builder from(Bitmap bitmap) {
- return new Palette.Builder(bitmap);
+ /** Start generating a {@link Palette} with the returned {@link Builder} instance. */
+ @NonNull
+ public static Builder from(@NonNull Bitmap bitmap, @NonNull Quantizer quantizer) {
+ return new Builder(bitmap, quantizer);
}
/**
* Generate a {@link Palette} from the pre-generated list of {@link Palette.Swatch} swatches.
- * This is useful for testing, or if you want to resurrect a {@link Palette} instance from a
- * list of swatches. Will return null if the {@code swatches} is null.
- */
- public static Palette from(List<Palette.Swatch> swatches) {
- return new Palette.Builder(swatches).generate();
- }
-
- /**
- * @deprecated Use {@link Palette.Builder} to generate the Palette.
- */
- @Deprecated
- public static Palette generate(Bitmap bitmap) {
- return from(bitmap).generate();
- }
-
- /**
- * @deprecated Use {@link Palette.Builder} to generate the Palette.
- */
- @Deprecated
- public static Palette generate(Bitmap bitmap, int numColors) {
- return from(bitmap).maximumColorCount(numColors).generate();
- }
-
- /**
- * @deprecated Use {@link Palette.Builder} to generate the Palette.
+ * This
+ * is useful for testing, or if you want to resurrect a {@link Palette} instance from a list of
+ * swatches. Will return null if the {@code swatches} is null.
*/
- @Deprecated
- public static AsyncTask<Bitmap, Void, Palette> generateAsync(
- Bitmap bitmap, Palette.PaletteAsyncListener listener) {
- return from(bitmap).generate(listener);
- }
-
- /**
- * @deprecated Use {@link Palette.Builder} to generate the Palette.
- */
- @Deprecated
- public static AsyncTask<Bitmap, Void, Palette> generateAsync(
- final Bitmap bitmap, final int numColors, final Palette.PaletteAsyncListener listener) {
- return from(bitmap).maximumColorCount(numColors).generate(listener);
+ @NonNull
+ public static Palette from(@NonNull List<Swatch> swatches) {
+ return new Builder(swatches).generate();
}
- private final List<Palette.Swatch> mSwatches;
- private final List<Target> mTargets;
+ private final List<Swatch> mSwatches;
- private final Map<Target, Palette.Swatch> mSelectedSwatches;
- private final SparseBooleanArray mUsedColors;
- private final Palette.Swatch mDominantSwatch;
+ @Nullable
+ private final Swatch mDominantSwatch;
- Palette(List<Palette.Swatch> swatches, List<Target> targets) {
+ Palette(List<Swatch> swatches) {
mSwatches = swatches;
- mTargets = targets;
-
- mUsedColors = new SparseBooleanArray();
- mSelectedSwatches = new ArrayMap<>();
-
mDominantSwatch = findDominantSwatch();
}
- /**
- * Returns all of the swatches which make up the palette.
- */
+ /** Returns all of the swatches which make up the palette. */
@NonNull
- public List<Palette.Swatch> getSwatches() {
+ public List<Swatch> getSwatches() {
return Collections.unmodifiableList(mSwatches);
}
- /**
- * Returns the targets used to generate this palette.
- */
- @NonNull
- public List<Target> getTargets() {
- return Collections.unmodifiableList(mTargets);
- }
-
- /**
- * Returns the most vibrant swatch in the palette. Might be null.
- *
- * @see Target#VIBRANT
- */
- @Nullable
- public Palette.Swatch getVibrantSwatch() {
- return getSwatchForTarget(Target.VIBRANT);
- }
-
- /**
- * Returns a light and vibrant swatch from the palette. Might be null.
- *
- * @see Target#LIGHT_VIBRANT
- */
- @Nullable
- public Palette.Swatch getLightVibrantSwatch() {
- return getSwatchForTarget(Target.LIGHT_VIBRANT);
- }
-
- /**
- * Returns a dark and vibrant swatch from the palette. Might be null.
- *
- * @see Target#DARK_VIBRANT
- */
- @Nullable
- public Palette.Swatch getDarkVibrantSwatch() {
- return getSwatchForTarget(Target.DARK_VIBRANT);
- }
-
- /**
- * Returns a muted swatch from the palette. Might be null.
- *
- * @see Target#MUTED
- */
- @Nullable
- public Palette.Swatch getMutedSwatch() {
- return getSwatchForTarget(Target.MUTED);
- }
-
- /**
- * Returns a muted and light swatch from the palette. Might be null.
- *
- * @see Target#LIGHT_MUTED
- */
- @Nullable
- public Palette.Swatch getLightMutedSwatch() {
- return getSwatchForTarget(Target.LIGHT_MUTED);
- }
-
- /**
- * Returns a muted and dark swatch from the palette. Might be null.
- *
- * @see Target#DARK_MUTED
- */
+ /** Returns the swatch with the highest population, or null if there are no swatches. */
@Nullable
- public Palette.Swatch getDarkMutedSwatch() {
- return getSwatchForTarget(Target.DARK_MUTED);
- }
-
- /**
- * Returns the most vibrant color in the palette as an RGB packed int.
- *
- * @param defaultColor value to return if the swatch isn't available
- * @see #getVibrantSwatch()
- */
- @ColorInt
- public int getVibrantColor(@ColorInt final int defaultColor) {
- return getColorForTarget(Target.VIBRANT, defaultColor);
- }
-
- /**
- * Returns a light and vibrant color from the palette as an RGB packed int.
- *
- * @param defaultColor value to return if the swatch isn't available
- * @see #getLightVibrantSwatch()
- */
- @ColorInt
- public int getLightVibrantColor(@ColorInt final int defaultColor) {
- return getColorForTarget(Target.LIGHT_VIBRANT, defaultColor);
- }
-
- /**
- * Returns a dark and vibrant color from the palette as an RGB packed int.
- *
- * @param defaultColor value to return if the swatch isn't available
- * @see #getDarkVibrantSwatch()
- */
- @ColorInt
- public int getDarkVibrantColor(@ColorInt final int defaultColor) {
- return getColorForTarget(Target.DARK_VIBRANT, defaultColor);
- }
-
- /**
- * Returns a muted color from the palette as an RGB packed int.
- *
- * @param defaultColor value to return if the swatch isn't available
- * @see #getMutedSwatch()
- */
- @ColorInt
- public int getMutedColor(@ColorInt final int defaultColor) {
- return getColorForTarget(Target.MUTED, defaultColor);
- }
-
- /**
- * Returns a muted and light color from the palette as an RGB packed int.
- *
- * @param defaultColor value to return if the swatch isn't available
- * @see #getLightMutedSwatch()
- */
- @ColorInt
- public int getLightMutedColor(@ColorInt final int defaultColor) {
- return getColorForTarget(Target.LIGHT_MUTED, defaultColor);
- }
-
- /**
- * Returns a muted and dark color from the palette as an RGB packed int.
- *
- * @param defaultColor value to return if the swatch isn't available
- * @see #getDarkMutedSwatch()
- */
- @ColorInt
- public int getDarkMutedColor(@ColorInt final int defaultColor) {
- return getColorForTarget(Target.DARK_MUTED, defaultColor);
- }
-
- /**
- * Returns the selected swatch for the given target from the palette, or {@code null} if one
- * could not be found.
- */
- @Nullable
- public Palette.Swatch getSwatchForTarget(@NonNull final Target target) {
- return mSelectedSwatches.get(target);
- }
-
- /**
- * Returns the selected color for the given target from the palette as an RGB packed int.
- *
- * @param defaultColor value to return if the swatch isn't available
- */
- @ColorInt
- public int getColorForTarget(@NonNull final Target target, @ColorInt final int defaultColor) {
- Palette.Swatch swatch = getSwatchForTarget(target);
- return swatch != null ? swatch.getRgb() : defaultColor;
- }
-
- /**
- * Returns the dominant swatch from the palette.
- *
- * <p>The dominant swatch is defined as the swatch with the greatest population (frequency)
- * within the palette.</p>
- */
- @Nullable
- public Palette.Swatch getDominantSwatch() {
+ public Swatch getDominantSwatch() {
return mDominantSwatch;
}
- /**
- * Returns the color of the dominant swatch from the palette, as an RGB packed int.
- *
- * @param defaultColor value to return if the swatch isn't available
- * @see #getDominantSwatch()
- */
- @ColorInt
- public int getDominantColor(@ColorInt int defaultColor) {
- return mDominantSwatch != null ? mDominantSwatch.getRgb() : defaultColor;
- }
-
- void generate() {
- // We need to make sure that the scored targets are generated first. This is so that
- // inherited targets have something to inherit from
- for (int i = 0, count = mTargets.size(); i < count; i++) {
- final Target target = mTargets.get(i);
- target.normalizeWeights();
- mSelectedSwatches.put(target, generateScoredTarget(target));
- }
- // We now clear out the used colors
- mUsedColors.clear();
- }
-
- private Palette.Swatch generateScoredTarget(final Target target) {
- final Palette.Swatch maxScoreSwatch = getMaxScoredSwatchForTarget(target);
- if (maxScoreSwatch != null && target.isExclusive()) {
- // If we have a swatch, and the target is exclusive, add the color to the used list
- mUsedColors.append(maxScoreSwatch.getRgb(), true);
- }
- return maxScoreSwatch;
- }
-
- private Palette.Swatch getMaxScoredSwatchForTarget(final Target target) {
- float maxScore = 0;
- Palette.Swatch maxScoreSwatch = null;
- for (int i = 0, count = mSwatches.size(); i < count; i++) {
- final Palette.Swatch swatch = mSwatches.get(i);
- if (shouldBeScoredForTarget(swatch, target)) {
- final float score = generateScore(swatch, target);
- if (maxScoreSwatch == null || score > maxScore) {
- maxScoreSwatch = swatch;
- maxScore = score;
- }
- }
- }
- return maxScoreSwatch;
- }
-
- private boolean shouldBeScoredForTarget(final Palette.Swatch swatch, final Target target) {
- // Check whether the HSL values are within the correct ranges, and this color hasn't
- // been used yet.
- final float hsl[] = swatch.getHsl();
- return hsl[1] >= target.getMinimumSaturation() && hsl[1] <= target.getMaximumSaturation()
- && hsl[2] >= target.getMinimumLightness() && hsl[2] <= target.getMaximumLightness()
- && !mUsedColors.get(swatch.getRgb());
- }
-
- private float generateScore(Palette.Swatch swatch, Target target) {
- final float[] hsl = swatch.getHsl();
-
- float saturationScore = 0;
- float luminanceScore = 0;
- float populationScore = 0;
-
- final int maxPopulation = mDominantSwatch != null ? mDominantSwatch.getPopulation() : 1;
-
- if (target.getSaturationWeight() > 0) {
- saturationScore = target.getSaturationWeight()
- * (1f - Math.abs(hsl[1] - target.getTargetSaturation()));
- }
- if (target.getLightnessWeight() > 0) {
- luminanceScore = target.getLightnessWeight()
- * (1f - Math.abs(hsl[2] - target.getTargetLightness()));
- }
- if (target.getPopulationWeight() > 0) {
- populationScore = target.getPopulationWeight()
- * (swatch.getPopulation() / (float) maxPopulation);
- }
-
- return saturationScore + luminanceScore + populationScore;
- }
-
- private Palette.Swatch findDominantSwatch() {
+ @Nullable
+ private Swatch findDominantSwatch() {
int maxPop = Integer.MIN_VALUE;
- Palette.Swatch maxSwatch = null;
+ Swatch maxSwatch = null;
for (int i = 0, count = mSwatches.size(); i < count; i++) {
- Palette.Swatch swatch = mSwatches.get(i);
+ Swatch swatch = mSwatches.get(i);
if (swatch.getPopulation() > maxPop) {
maxSwatch = swatch;
maxPop = swatch.getPopulation();
@@ -433,148 +122,42 @@ public final class Palette {
return maxSwatch;
}
- private static float[] copyHslValues(Palette.Swatch color) {
- final float[] newHsl = new float[3];
- System.arraycopy(color.getHsl(), 0, newHsl, 0, 3);
- return newHsl;
- }
-
/**
* Represents a color swatch generated from an image's palette. The RGB color can be retrieved
- * by calling {@link #getRgb()}.
+ * by
+ * calling {@link #getInt()}.
*/
- public static final class Swatch {
- private final int mRed, mGreen, mBlue;
- private final int mRgb;
+ public static class Swatch {
+ private final Color mColor;
private final int mPopulation;
- private boolean mGeneratedTextColors;
- private int mTitleTextColor;
- private int mBodyTextColor;
-
- private float[] mHsl;
-
- public Swatch(@ColorInt int color, int population) {
- mRed = Color.red(color);
- mGreen = Color.green(color);
- mBlue = Color.blue(color);
- mRgb = color;
- mPopulation = population;
- }
- Swatch(int red, int green, int blue, int population) {
- mRed = red;
- mGreen = green;
- mBlue = blue;
- mRgb = Color.rgb(red, green, blue);
+ public Swatch(@ColorInt int colorInt, int population) {
+ mColor = Color.valueOf(colorInt);
mPopulation = population;
}
- Swatch(float[] hsl, int population) {
- this(ColorUtils.HSLToColor(hsl), population);
- mHsl = hsl;
- }
-
- /**
- * @return this swatch's RGB color value
- */
+ /** @return this swatch's RGB color value */
@ColorInt
- public int getRgb() {
- return mRgb;
+ public int getInt() {
+ return mColor.toArgb();
}
- /**
- * Return this swatch's HSL values.
- * hsv[0] is Hue [0 .. 360)
- * hsv[1] is Saturation [0...1]
- * hsv[2] is Lightness [0...1]
- */
- public float[] getHsl() {
- if (mHsl == null) {
- mHsl = new float[3];
- }
- ColorUtils.RGBToHSL(mRed, mGreen, mBlue, mHsl);
- return mHsl;
- }
-
- /**
- * @return the number of pixels represented by this swatch
- */
+ /** @return the number of pixels represented by this swatch */
public int getPopulation() {
return mPopulation;
}
- /**
- * Returns an appropriate color to use for any 'title' text which is displayed over this
- * {@link Palette.Swatch}'s color. This color is guaranteed to have sufficient contrast.
- */
- @ColorInt
- public int getTitleTextColor() {
- ensureTextColorsGenerated();
- return mTitleTextColor;
- }
-
- /**
- * Returns an appropriate color to use for any 'body' text which is displayed over this
- * {@link Palette.Swatch}'s color. This color is guaranteed to have sufficient contrast.
- */
- @ColorInt
- public int getBodyTextColor() {
- ensureTextColorsGenerated();
- return mBodyTextColor;
- }
-
- private void ensureTextColorsGenerated() {
- if (!mGeneratedTextColors) {
- // First check white, as most colors will be dark
- final int lightBodyAlpha = ColorUtils.calculateMinimumAlpha(
- Color.WHITE, mRgb, MIN_CONTRAST_BODY_TEXT);
- final int lightTitleAlpha = ColorUtils.calculateMinimumAlpha(
- Color.WHITE, mRgb, MIN_CONTRAST_TITLE_TEXT);
-
- if (lightBodyAlpha != -1 && lightTitleAlpha != -1) {
- // If we found valid light values, use them and return
- mBodyTextColor = ColorUtils.setAlphaComponent(Color.WHITE, lightBodyAlpha);
- mTitleTextColor = ColorUtils.setAlphaComponent(Color.WHITE, lightTitleAlpha);
- mGeneratedTextColors = true;
- return;
- }
-
- final int darkBodyAlpha = ColorUtils.calculateMinimumAlpha(
- Color.BLACK, mRgb, MIN_CONTRAST_BODY_TEXT);
- final int darkTitleAlpha = ColorUtils.calculateMinimumAlpha(
- Color.BLACK, mRgb, MIN_CONTRAST_TITLE_TEXT);
-
- if (darkBodyAlpha != -1 && darkTitleAlpha != -1) {
- // If we found valid dark values, use them and return
- mBodyTextColor = ColorUtils.setAlphaComponent(Color.BLACK, darkBodyAlpha);
- mTitleTextColor = ColorUtils.setAlphaComponent(Color.BLACK, darkTitleAlpha);
- mGeneratedTextColors = true;
- return;
- }
-
- // If we reach here then we can not find title and body values which use the same
- // lightness, we need to use mismatched values
- mBodyTextColor = lightBodyAlpha != -1
- ? ColorUtils.setAlphaComponent(Color.WHITE, lightBodyAlpha)
- : ColorUtils.setAlphaComponent(Color.BLACK, darkBodyAlpha);
- mTitleTextColor = lightTitleAlpha != -1
- ? ColorUtils.setAlphaComponent(Color.WHITE, lightTitleAlpha)
- : ColorUtils.setAlphaComponent(Color.BLACK, darkTitleAlpha);
- mGeneratedTextColors = true;
- }
- }
-
@Override
public String toString() {
return new StringBuilder(getClass().getSimpleName())
- .append(" [RGB: #").append(Integer.toHexString(getRgb())).append(']')
- .append(" [HSL: ").append(Arrays.toString(getHsl())).append(']')
- .append(" [Population: ").append(mPopulation).append(']')
- .append(" [Title Text: #").append(Integer.toHexString(getTitleTextColor()))
+ .append(" [")
+ .append(mColor)
+ .append(']')
+ .append(" [Population: ")
+ .append(mPopulation)
.append(']')
- .append(" [Body Text: #").append(Integer.toHexString(getBodyTextColor()))
- .append(']').toString();
+ .toString();
}
@Override
@@ -586,243 +169,168 @@ public final class Palette {
return false;
}
- Palette.Swatch
- swatch = (Palette.Swatch) o;
- return mPopulation == swatch.mPopulation && mRgb == swatch.mRgb;
+ Swatch swatch = (Swatch) o;
+ return mPopulation == swatch.mPopulation && mColor.toArgb() == swatch.mColor.toArgb();
}
@Override
public int hashCode() {
- return 31 * mRgb + mPopulation;
+ return 31 * mColor.toArgb() + mPopulation;
}
}
- /**
- * Builder class for generating {@link Palette} instances.
- */
- public static final class Builder {
- private final List<Palette.Swatch> mSwatches;
+ /** Builder class for generating {@link Palette} instances. */
+ public static class Builder {
+ @Nullable
+ private final List<Swatch> mSwatches;
+ @Nullable
private final Bitmap mBitmap;
+ @Nullable
+ private Quantizer mQuantizer = new ColorCutQuantizer();
- private final List<Target> mTargets = new ArrayList<>();
private int mMaxColors = DEFAULT_CALCULATE_NUMBER_COLORS;
private int mResizeArea = DEFAULT_RESIZE_BITMAP_AREA;
private int mResizeMaxDimension = -1;
- private final List<Palette.Filter> mFilters = new ArrayList<>();
+ @Nullable
private Rect mRegion;
- private Quantizer mQuantizer;
-
- /**
- * Construct a new {@link Palette.Builder} using a source {@link Bitmap}
- */
- public Builder(Bitmap bitmap) {
+ /** Construct a new {@link Builder} using a source {@link Bitmap} */
+ public Builder(@NonNull Bitmap bitmap, @NonNull Quantizer quantizer) {
if (bitmap == null || bitmap.isRecycled()) {
throw new IllegalArgumentException("Bitmap is not valid");
}
- mFilters.add(DEFAULT_FILTER);
- mBitmap = bitmap;
mSwatches = null;
-
- // Add the default targets
- mTargets.add(Target.LIGHT_VIBRANT);
- mTargets.add(Target.VIBRANT);
- mTargets.add(Target.DARK_VIBRANT);
- mTargets.add(Target.LIGHT_MUTED);
- mTargets.add(Target.MUTED);
- mTargets.add(Target.DARK_MUTED);
+ mBitmap = bitmap;
+ mQuantizer = quantizer == null ? new ColorCutQuantizer() : quantizer;
}
/**
- * Construct a new {@link Palette.Builder} using a list of {@link Palette.Swatch} instances.
- * Typically only used for testing.
+ * Construct a new {@link Builder} using a list of {@link Swatch} instances. Typically only
+ * used
+ * for testing.
*/
- public Builder(List<Palette.Swatch> swatches) {
+ public Builder(@NonNull List<Swatch> swatches) {
if (swatches == null || swatches.isEmpty()) {
throw new IllegalArgumentException("List of Swatches is not valid");
}
- mFilters.add(DEFAULT_FILTER);
mSwatches = swatches;
mBitmap = null;
+ mQuantizer = null;
}
/**
- * Set the maximum number of colors to use in the quantization step when using a
- * {@link android.graphics.Bitmap} as the source.
- * <p>
- * Good values for depend on the source image type. For landscapes, good values are in
- * the range 10-16. For images which are largely made up of people's faces then this
- * value should be increased to ~24.
+ * Set the maximum number of colors to use in the quantization step when using a {@link
+ * android.graphics.Bitmap} as the source.
+ *
+ * <p>Good values for depend on the source image type. For landscapes, good values are in
+ * the
+ * range 10-16. For images which are largely made up of people's faces then this value
+ * should be
+ * increased to ~24.
*/
@NonNull
- public Palette.Builder maximumColorCount(int colors) {
+ public Builder maximumColorCount(int colors) {
mMaxColors = colors;
return this;
}
/**
- * Set the resize value when using a {@link android.graphics.Bitmap} as the source.
- * If the bitmap's largest dimension is greater than the value specified, then the bitmap
- * will be resized so that its largest dimension matches {@code maxDimension}. If the
- * bitmap is smaller or equal, the original is used as-is.
- *
- * @deprecated Using {@link #resizeBitmapArea(int)} is preferred since it can handle
- * abnormal aspect ratios more gracefully.
+ * Set the resize value when using a {@link android.graphics.Bitmap} as the source. If the
+ * bitmap's largest dimension is greater than the value specified, then the bitmap will be
+ * resized so that its largest dimension matches {@code maxDimension}. If the bitmap is
+ * smaller
+ * or equal, the original is used as-is.
*
* @param maxDimension the number of pixels that the max dimension should be scaled down to,
- * or any value <= 0 to disable resizing.
+ * or
+ * any value <= 0 to disable resizing.
+ * @deprecated Using {@link #resizeBitmapArea(int)} is preferred since it can handle
+ * abnormal
+ * aspect ratios more gracefully.
*/
@NonNull
@Deprecated
- public Palette.Builder resizeBitmapSize(final int maxDimension) {
+ public Builder resizeBitmapSize(int maxDimension) {
mResizeMaxDimension = maxDimension;
mResizeArea = -1;
return this;
}
/**
- * Set the resize value when using a {@link android.graphics.Bitmap} as the source.
- * If the bitmap's area is greater than the value specified, then the bitmap
- * will be resized so that its area matches {@code area}. If the
- * bitmap is smaller or equal, the original is used as-is.
- * <p>
- * This value has a large effect on the processing time. The larger the resized image is,
- * the greater time it will take to generate the palette. The smaller the image is, the
- * more detail is lost in the resulting image and thus less precision for color selection.
+ * Set the resize value when using a {@link android.graphics.Bitmap} as the source. If the
+ * bitmap's area is greater than the value specified, then the bitmap will be resized so
+ * that
+ * its area matches {@code area}. If the bitmap is smaller or equal, the original is used
+ * as-is.
+ *
+ * <p>This value has a large effect on the processing time. The larger the resized image is,
+ * the
+ * greater time it will take to generate the palette. The smaller the image is, the more
+ * detail
+ * is lost in the resulting image and thus less precision for color selection.
*
* @param area the number of pixels that the intermediary scaled down Bitmap should cover,
- * or any value <= 0 to disable resizing.
+ * or
+ * any value <= 0 to disable resizing.
*/
@NonNull
- public Palette.Builder resizeBitmapArea(final int area) {
+ public Builder resizeBitmapArea(int area) {
mResizeArea = area;
mResizeMaxDimension = -1;
return this;
}
/**
- * Clear all added filters. This includes any default filters added automatically by
- * {@link Palette}.
- */
- @NonNull
- public Palette.Builder clearFilters() {
- mFilters.clear();
- return this;
- }
-
- /**
- * Add a filter to be able to have fine grained control over which colors are
- * allowed in the resulting palette.
- *
- * @param filter filter to add.
- */
- @NonNull
- public Palette.Builder addFilter(
- Palette.Filter filter) {
- if (filter != null) {
- mFilters.add(filter);
- }
- return this;
- }
-
- /**
- * Set a specific quantization algorithm. {@link ColorCutQuantizer} will
- * be used if unspecified.
- *
- * @param quantizer Quantizer implementation.
- */
- @NonNull
- public Palette.Builder setQuantizer(Quantizer quantizer) {
- mQuantizer = quantizer;
- return this;
- }
-
- /**
* Set a region of the bitmap to be used exclusively when calculating the palette.
- * <p>This only works when the original input is a {@link Bitmap}.</p>
*
- * @param left The left side of the rectangle used for the region.
- * @param top The top of the rectangle used for the region.
- * @param right The right side of the rectangle used for the region.
+ * <p>This only works when the original input is a {@link Bitmap}.
+ *
+ * @param left The left side of the rectangle used for the region.
+ * @param top The top of the rectangle used for the region.
+ * @param right The right side of the rectangle used for the region.
* @param bottom The bottom of the rectangle used for the region.
*/
@NonNull
- public Palette.Builder setRegion(int left, int top, int right, int bottom) {
+ public Builder setRegion(@Px int left, @Px int top, @Px int right, @Px int bottom) {
if (mBitmap != null) {
if (mRegion == null) mRegion = new Rect();
// Set the Rect to be initially the whole Bitmap
mRegion.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
// Now just get the intersection with the region
if (!mRegion.intersect(left, top, right, bottom)) {
- throw new IllegalArgumentException("The given region must intersect with "
- + "the Bitmap's dimensions.");
+ throw new IllegalArgumentException(
+ "The given region must intersect with " + "the Bitmap's dimensions.");
}
}
return this;
}
- /**
- * Clear any previously region set via {@link #setRegion(int, int, int, int)}.
- */
+ /** Clear any previously region set via {@link #setRegion(int, int, int, int)}. */
@NonNull
- public Palette.Builder clearRegion() {
+ public Builder clearRegion() {
mRegion = null;
return this;
}
- /**
- * Add a target profile to be generated in the palette.
- *
- * <p>You can retrieve the result via {@link Palette#getSwatchForTarget(Target)}.</p>
- */
- @NonNull
- public Palette.Builder addTarget(@NonNull final Target target) {
- if (!mTargets.contains(target)) {
- mTargets.add(target);
- }
- return this;
- }
- /**
- * Clear all added targets. This includes any default targets added automatically by
- * {@link Palette}.
- */
- @NonNull
- public Palette.Builder clearTargets() {
- if (mTargets != null) {
- mTargets.clear();
- }
- return this;
- }
-
- /**
- * Generate and return the {@link Palette} synchronously.
- */
+ /** Generate and return the {@link Palette} synchronously. */
@NonNull
public Palette generate() {
- final TimingLogger logger = LOG_TIMINGS
- ? new TimingLogger(LOG_TAG, "Generation")
- : null;
-
- List<Palette.Swatch> swatches;
+ List<Swatch> swatches;
if (mBitmap != null) {
// We have a Bitmap so we need to use quantization to reduce the number of colors
// First we'll scale down the bitmap if needed
- final Bitmap bitmap = scaleBitmapDown(mBitmap);
-
- if (logger != null) {
- logger.addSplit("Processed Bitmap");
- }
+ Bitmap bitmap = scaleBitmapDown(mBitmap);
- final Rect region = mRegion;
+ Rect region = mRegion;
if (bitmap != mBitmap && region != null) {
// If we have a scaled bitmap and a selected region, we need to scale down the
// region to match the new scale
- final double scale = bitmap.getWidth() / (double) mBitmap.getWidth();
+ double scale = bitmap.getWidth() / (double) mBitmap.getWidth();
region.left = (int) Math.floor(region.left * scale);
region.top = (int) Math.floor(region.top * scale);
region.right = Math.min((int) Math.ceil(region.right * scale),
@@ -832,54 +340,47 @@ public final class Palette {
}
// Now generate a quantizer from the Bitmap
- if (mQuantizer == null) {
- mQuantizer = new ColorCutQuantizer();
- }
- mQuantizer.quantize(getPixelsFromBitmap(bitmap),
- mMaxColors, mFilters.isEmpty() ? null :
- mFilters.toArray(new Palette.Filter[mFilters.size()]));
+ mQuantizer.quantize(
+ getPixelsFromBitmap(bitmap),
+ mMaxColors);
// If created a new bitmap, recycle it
if (bitmap != mBitmap) {
bitmap.recycle();
}
-
swatches = mQuantizer.getQuantizedColors();
-
- if (logger != null) {
- logger.addSplit("Color quantization completed");
- }
- } else {
+ } else if (mSwatches != null) {
// Else we're using the provided swatches
swatches = mSwatches;
+ } else {
+ // The constructors enforce either a bitmap or swatches are present.
+ throw new AssertionError();
}
// Now create a Palette instance
- final Palette p = new Palette(swatches, mTargets);
+ Palette p = new Palette(swatches);
// And make it generate itself
- p.generate();
-
- if (logger != null) {
- logger.addSplit("Created Palette");
- logger.dumpToLog();
- }
return p;
}
/**
- * Generate the {@link Palette} asynchronously. The provided listener's
- * {@link Palette.PaletteAsyncListener#onGenerated} method will be called with the palette when
- * generated.
+ * Generate the {@link Palette} asynchronously. The provided listener's {@link
+ * PaletteAsyncListener#onGenerated} method will be called with the palette when generated.
+ *
+ * @deprecated Use the standard <code>java.util.concurrent</code> or <a
+ * href="https://developer.android.com/topic/libraries/architecture/coroutines">Kotlin
+ * concurrency utilities</a> to call {@link #generate()} instead.
*/
@NonNull
- public AsyncTask<Bitmap, Void, Palette> generate(final Palette.PaletteAsyncListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException("listener can not be null");
- }
+ @Deprecated
+ public android.os.AsyncTask<Bitmap, Void, Palette> generate(
+ @NonNull PaletteAsyncListener listener) {
+ assert (listener != null);
- return new AsyncTask<Bitmap, Void, Palette>() {
+ return new android.os.AsyncTask<Bitmap, Void, Palette>() {
@Override
+ @Nullable
protected Palette doInBackground(Bitmap... params) {
try {
return generate();
@@ -890,16 +391,16 @@ public final class Palette {
}
@Override
- protected void onPostExecute(Palette colorExtractor) {
+ protected void onPostExecute(@Nullable Palette colorExtractor) {
listener.onGenerated(colorExtractor);
}
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mBitmap);
+ }.executeOnExecutor(android.os.AsyncTask.THREAD_POOL_EXECUTOR, mBitmap);
}
private int[] getPixelsFromBitmap(Bitmap bitmap) {
- final int bitmapWidth = bitmap.getWidth();
- final int bitmapHeight = bitmap.getHeight();
- final int[] pixels = new int[bitmapWidth * bitmapHeight];
+ int bitmapWidth = bitmap.getWidth();
+ int bitmapHeight = bitmap.getHeight();
+ int[] pixels = new int[bitmapWidth * bitmapHeight];
bitmap.getPixels(pixels, 0, bitmapWidth, 0, 0, bitmapWidth, bitmapHeight);
if (mRegion == null) {
@@ -908,32 +409,34 @@ public final class Palette {
} else {
// If we do have a region, lets create a subset array containing only the region's
// pixels
- final int regionWidth = mRegion.width();
- final int regionHeight = mRegion.height();
+ int regionWidth = mRegion.width();
+ int regionHeight = mRegion.height();
// pixels contains all of the pixels, so we need to iterate through each row and
// copy the regions pixels into a new smaller array
- final int[] subsetPixels = new int[regionWidth * regionHeight];
+ int[] subsetPixels = new int[regionWidth * regionHeight];
for (int row = 0; row < regionHeight; row++) {
- System.arraycopy(pixels, ((row + mRegion.top) * bitmapWidth) + mRegion.left,
- subsetPixels, row * regionWidth, regionWidth);
+ System.arraycopy(
+ pixels,
+ ((row + mRegion.top) * bitmapWidth) + mRegion.left,
+ subsetPixels,
+ row * regionWidth,
+ regionWidth);
}
return subsetPixels;
}
}
- /**
- * Scale the bitmap down as needed.
- */
- private Bitmap scaleBitmapDown(final Bitmap bitmap) {
+ /** Scale the bitmap down as needed. */
+ private Bitmap scaleBitmapDown(Bitmap bitmap) {
double scaleRatio = -1;
if (mResizeArea > 0) {
- final int bitmapArea = bitmap.getWidth() * bitmap.getHeight();
+ int bitmapArea = bitmap.getWidth() * bitmap.getHeight();
if (bitmapArea > mResizeArea) {
scaleRatio = Math.sqrt(mResizeArea / (double) bitmapArea);
}
} else if (mResizeMaxDimension > 0) {
- final int maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight());
+ int maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight());
if (maxDimension > mResizeMaxDimension) {
scaleRatio = mResizeMaxDimension / (double) maxDimension;
}
@@ -944,11 +447,13 @@ public final class Palette {
return bitmap;
}
- return Bitmap.createScaledBitmap(bitmap,
+ return Bitmap.createScaledBitmap(
+ bitmap,
(int) Math.ceil(bitmap.getWidth() * scaleRatio),
(int) Math.ceil(bitmap.getHeight() * scaleRatio),
false);
}
+
}
/**
@@ -961,9 +466,7 @@ public final class Palette {
*
* @param rgb the color in RGB888.
* @param hsl HSL representation of the color.
- *
* @return true if the color is allowed, false if not.
- *
* @see Palette.Builder#addFilter(Palette.Filter)
*/
boolean isAllowed(int rgb, float[] hsl);
@@ -1004,3 +507,4 @@ public final class Palette {
}
};
}
+
diff --git a/core/java/com/android/internal/graphics/palette/Quantizer.java b/core/java/com/android/internal/graphics/palette/Quantizer.java
index db60f2e9dc69..a219ea3aa7d0 100644
--- a/core/java/com/android/internal/graphics/palette/Quantizer.java
+++ b/core/java/com/android/internal/graphics/palette/Quantizer.java
@@ -22,6 +22,15 @@ import java.util.List;
* Definition of an algorithm that receives pixels and outputs a list of colors.
*/
public interface Quantizer {
- void quantize(final int[] pixels, final int maxColors, final Palette.Filter[] filters);
+ /**
+ * Create colors representative of the colors present in pixels.
+ * @param pixels Set of ARGB representation of a color.
+ * @param maxColors number of colors to generate
+ */
+ void quantize(int[] pixels, int maxColors);
+
+ /**
+ * List of colors generated by previous call to quantize.
+ */
List<Palette.Swatch> getQuantizedColors();
}
diff --git a/core/java/com/android/internal/graphics/palette/Target.java b/core/java/com/android/internal/graphics/palette/Target.java
index 0540d80ef6f0..96e7faa81c3a 100644
--- a/core/java/com/android/internal/graphics/palette/Target.java
+++ b/core/java/com/android/internal/graphics/palette/Target.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,368 +16,234 @@
package com.android.internal.graphics.palette;
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
/**
- * Copied from: frameworks/support/v7/palette/src/main/java/android/support/v7/graphics/Target.java
- *
- * A class which allows custom selection of colors in a {@link Palette}'s generation. Instances
- * can be created via the {@link android.support.v7.graphics.Target.Builder} class.
- *
- * <p>To use the target, use the {@link Palette.Builder#addTarget(Target)} API when building a
- * Palette.</p>
+ * A class which allows custom selection of colors in a {@link Palette}'s generation. Instances can
+ * be created via the {@link Builder} class.
*/
-public final class Target {
-
- private static final float TARGET_DARK_LUMA = 0.26f;
- private static final float MAX_DARK_LUMA = 0.45f;
-
- private static final float MIN_LIGHT_LUMA = 0.55f;
- private static final float TARGET_LIGHT_LUMA = 0.74f;
-
- private static final float MIN_NORMAL_LUMA = 0.3f;
- private static final float TARGET_NORMAL_LUMA = 0.5f;
- private static final float MAX_NORMAL_LUMA = 0.7f;
-
- private static final float TARGET_MUTED_SATURATION = 0.3f;
- private static final float MAX_MUTED_SATURATION = 0.4f;
-
- private static final float TARGET_VIBRANT_SATURATION = 1f;
- private static final float MIN_VIBRANT_SATURATION = 0.35f;
-
- private static final float WEIGHT_SATURATION = 0.24f;
- private static final float WEIGHT_LUMA = 0.52f;
- private static final float WEIGHT_POPULATION = 0.24f;
-
- static final int INDEX_MIN = 0;
- static final int INDEX_TARGET = 1;
- static final int INDEX_MAX = 2;
-
- static final int INDEX_WEIGHT_SAT = 0;
- static final int INDEX_WEIGHT_LUMA = 1;
- static final int INDEX_WEIGHT_POP = 2;
-
- /**
- * A target which has the characteristics of a vibrant color which is light in luminance.
- */
- public static final Target LIGHT_VIBRANT;
-
- /**
- * A target which has the characteristics of a vibrant color which is neither light or dark.
- */
- public static final Target VIBRANT;
-
- /**
- * A target which has the characteristics of a vibrant color which is dark in luminance.
- */
- public static final Target DARK_VIBRANT;
-
- /**
- * A target which has the characteristics of a muted color which is light in luminance.
- */
- public static final Target LIGHT_MUTED;
-
- /**
- * A target which has the characteristics of a muted color which is neither light or dark.
- */
- public static final Target MUTED;
-
- /**
- * A target which has the characteristics of a muted color which is dark in luminance.
- */
- public static final Target DARK_MUTED;
- static {
- LIGHT_VIBRANT = new Target();
- setDefaultLightLightnessValues(LIGHT_VIBRANT);
- setDefaultVibrantSaturationValues(LIGHT_VIBRANT);
-
- VIBRANT = new Target();
- setDefaultNormalLightnessValues(VIBRANT);
- setDefaultVibrantSaturationValues(VIBRANT);
-
- DARK_VIBRANT = new Target();
- setDefaultDarkLightnessValues(DARK_VIBRANT);
- setDefaultVibrantSaturationValues(DARK_VIBRANT);
-
- LIGHT_MUTED = new Target();
- setDefaultLightLightnessValues(LIGHT_MUTED);
- setDefaultMutedSaturationValues(LIGHT_MUTED);
-
- MUTED = new Target();
- setDefaultNormalLightnessValues(MUTED);
- setDefaultMutedSaturationValues(MUTED);
-
- DARK_MUTED = new Target();
- setDefaultDarkLightnessValues(DARK_MUTED);
- setDefaultMutedSaturationValues(DARK_MUTED);
- }
-
- final float[] mSaturationTargets = new float[3];
- final float[] mLightnessTargets = new float[3];
- final float[] mWeights = new float[3];
- boolean mIsExclusive = true; // default to true
+public final class Target {
+ private static final float WEIGHT_CHROMA = 0.5f;
+ private static final float WEIGHT_RELATIVE_LUMINANCE = 0.5f;
+ private static final float WEIGHT_POPULATION = 0.3f;
+ private static final float WEIGHT_HUE = 0.2f;
+
+ // Arbitrarily chosen, except max - CAM16 chroma has a ceiling of 130, based on unit testing.
+ private static final float DEFAULT_CHROMA_MIN = 0.f;
+ private static final float DEFAULT_CHROMA_MAX = 130.f;
+ private static final float DEFAULT_CHROMA_TARGET = 30.f;
+
+ private float mTargetRelativeLuminance = -1.0f;
+ private float mChromaWeight;
+ private float mChromaTarget;
+ private float mChromaMin;
+ private float mChromaMax;
+ private float mRelativeLuminanceWeight;
+ private float mPopulationWeight;
+ private float mHueWeight;
+ private float mTargetHue;
Target() {
- setTargetDefaultValues(mSaturationTargets);
- setTargetDefaultValues(mLightnessTargets);
- setDefaultWeights();
+ mChromaMax = DEFAULT_CHROMA_MAX;
+ mChromaMin = DEFAULT_CHROMA_MIN;
+ mChromaTarget = DEFAULT_CHROMA_TARGET;
+ mChromaWeight = WEIGHT_CHROMA;
+ mRelativeLuminanceWeight = WEIGHT_RELATIVE_LUMINANCE;
+ mPopulationWeight = WEIGHT_POPULATION;
+ mHueWeight = WEIGHT_HUE;
}
- Target(Target from) {
- System.arraycopy(from.mSaturationTargets, 0, mSaturationTargets, 0,
- mSaturationTargets.length);
- System.arraycopy(from.mLightnessTargets, 0, mLightnessTargets, 0,
- mLightnessTargets.length);
- System.arraycopy(from.mWeights, 0, mWeights, 0, mWeights.length);
+ Target(@NonNull Target from) {
+ mTargetRelativeLuminance = from.mTargetRelativeLuminance;
+ mChromaWeight = from.mChromaWeight;
+ mRelativeLuminanceWeight = from.mRelativeLuminanceWeight;
+ mPopulationWeight = from.mPopulationWeight;
+ mHueWeight = from.mHueWeight;
+ mChromaTarget = from.mChromaTarget;
+ mChromaMin = from.mChromaMin;
+ mChromaMax = from.mChromaMax;
}
- /**
- * The minimum saturation value for this target.
- */
- @FloatRange(from = 0, to = 1)
- public float getMinimumSaturation() {
- return mSaturationTargets[INDEX_MIN];
+ /** The relative luminance value for this target. */
+ @FloatRange(from = 0, to = 100)
+ public float getTargetRelativeLuminance() {
+ return mTargetRelativeLuminance;
}
- /**
- * The target saturation value for this target.
- */
- @FloatRange(from = 0, to = 1)
- public float getTargetSaturation() {
- return mSaturationTargets[INDEX_TARGET];
+ /** The relative luminance value for this target. */
+ @FloatRange(from = 0, to = 100)
+ public float getTargetPerceptualLuminance() {
+ return Contrast.yToLstar(mTargetRelativeLuminance);
}
- /**
- * The maximum saturation value for this target.
- */
- @FloatRange(from = 0, to = 1)
- public float getMaximumSaturation() {
- return mSaturationTargets[INDEX_MAX];
+ /** The minimum chroma value for this target. */
+ @FloatRange(from = 0, to = 100)
+ public float getMinimumChroma() {
+ return mChromaMin;
}
- /**
- * The minimum lightness value for this target.
- */
- @FloatRange(from = 0, to = 1)
- public float getMinimumLightness() {
- return mLightnessTargets[INDEX_MIN];
+ /** The target chroma value for this target. */
+ @FloatRange(from = 0, to = 100)
+ public float getTargetChroma() {
+ return mChromaTarget;
}
- /**
- * The target lightness value for this target.
- */
- @FloatRange(from = 0, to = 1)
- public float getTargetLightness() {
- return mLightnessTargets[INDEX_TARGET];
+ /** The maximum chroma value for this target. */
+ @FloatRange(from = 0, to = 130)
+ public float getMaximumChroma() {
+ return mChromaMax;
}
- /**
- * The maximum lightness value for this target.
- */
- @FloatRange(from = 0, to = 1)
- public float getMaximumLightness() {
- return mLightnessTargets[INDEX_MAX];
+ /** The target hue value for this target. */
+ @FloatRange(from = 0, to = 100)
+ public float getTargetHue() {
+ return mTargetHue;
}
/**
- * Returns the weight of importance that this target places on a color's saturation within
- * the image.
+ * Returns the weight of importance that this target places on a color's chroma within the
+ * image.
*
* <p>The larger the weight, relative to the other weights, the more important that a color
- * being close to the target value has on selection.</p>
+ * being
+ * close to the target value has on selection.
*
- * @see #getTargetSaturation()
+ * @see #getTargetChroma()
*/
- public float getSaturationWeight() {
- return mWeights[INDEX_WEIGHT_SAT];
+ public float getChromaWeight() {
+ return mChromaWeight;
}
/**
- * Returns the weight of importance that this target places on a color's lightness within
- * the image.
+ * Returns the weight of importance that this target places on a color's lightness within the
+ * image.
*
* <p>The larger the weight, relative to the other weights, the more important that a color
- * being close to the target value has on selection.</p>
+ * being
+ * close to the target value has on selection.
*
- * @see #getTargetLightness()
+ * @see #getTargetRelativeLuminance()
*/
public float getLightnessWeight() {
- return mWeights[INDEX_WEIGHT_LUMA];
+ return mRelativeLuminanceWeight;
}
/**
- * Returns the weight of importance that this target places on a color's population within
- * the image.
+ * Returns the weight of importance that this target places on a color's population within the
+ * image.
*
- * <p>The larger the weight, relative to the other weights, the more important that a
- * color's population being close to the most populous has on selection.</p>
+ * <p>The larger the weight, relative to the other weights, the more important that a color's
+ * population being close to the most populous has on selection.
*/
public float getPopulationWeight() {
- return mWeights[INDEX_WEIGHT_POP];
+ return mPopulationWeight;
}
/**
- * Returns whether any color selected for this target is exclusive for this target only.
+ * Returns the weight of importance that this target places on a color's hue.
*
- * <p>If false, then the color can be selected for other targets.</p>
+ * <p>The larger the weight, relative to the other weights, the more important that a color's
+ * hue being close to the desired hue has on selection.
*/
- public boolean isExclusive() {
- return mIsExclusive;
+ public float getHueWeight() {
+ return mHueWeight;
}
- private static void setTargetDefaultValues(final float[] values) {
- values[INDEX_MIN] = 0f;
- values[INDEX_TARGET] = 0.5f;
- values[INDEX_MAX] = 1f;
- }
-
- private void setDefaultWeights() {
- mWeights[INDEX_WEIGHT_SAT] = WEIGHT_SATURATION;
- mWeights[INDEX_WEIGHT_LUMA] = WEIGHT_LUMA;
- mWeights[INDEX_WEIGHT_POP] = WEIGHT_POPULATION;
- }
- void normalizeWeights() {
- float sum = 0;
- for (int i = 0, z = mWeights.length; i < z; i++) {
- float weight = mWeights[i];
- if (weight > 0) {
- sum += weight;
- }
- }
- if (sum != 0) {
- for (int i = 0, z = mWeights.length; i < z; i++) {
- if (mWeights[i] > 0) {
- mWeights[i] /= sum;
- }
- }
- }
- }
-
- private static void setDefaultDarkLightnessValues(Target target) {
- target.mLightnessTargets[INDEX_TARGET] = TARGET_DARK_LUMA;
- target.mLightnessTargets[INDEX_MAX] = MAX_DARK_LUMA;
- }
-
- private static void setDefaultNormalLightnessValues(Target target) {
- target.mLightnessTargets[INDEX_MIN] = MIN_NORMAL_LUMA;
- target.mLightnessTargets[INDEX_TARGET] = TARGET_NORMAL_LUMA;
- target.mLightnessTargets[INDEX_MAX] = MAX_NORMAL_LUMA;
- }
-
- private static void setDefaultLightLightnessValues(Target target) {
- target.mLightnessTargets[INDEX_MIN] = MIN_LIGHT_LUMA;
- target.mLightnessTargets[INDEX_TARGET] = TARGET_LIGHT_LUMA;
- }
-
- private static void setDefaultVibrantSaturationValues(Target target) {
- target.mSaturationTargets[INDEX_MIN] = MIN_VIBRANT_SATURATION;
- target.mSaturationTargets[INDEX_TARGET] = TARGET_VIBRANT_SATURATION;
- }
-
- private static void setDefaultMutedSaturationValues(Target target) {
- target.mSaturationTargets[INDEX_TARGET] = TARGET_MUTED_SATURATION;
- target.mSaturationTargets[INDEX_MAX] = MAX_MUTED_SATURATION;
- }
-
- /**
- * Builder class for generating custom {@link Target} instances.
- */
- public final static class Builder {
+ /** Builder class for generating custom {@link Target} instances. */
+ public static class Builder {
private final Target mTarget;
- /**
- * Create a new {@link Target} builder from scratch.
- */
+ /** Create a new {@link Target} builder from scratch. */
public Builder() {
mTarget = new Target();
}
- /**
- * Create a new builder based on an existing {@link Target}.
- */
- public Builder(Target target) {
+ /** Create a new builder based on an existing {@link Target}. */
+ public Builder(@NonNull Target target) {
mTarget = new Target(target);
}
- /**
- * Set the minimum saturation value for this target.
- */
- public Target.Builder setMinimumSaturation(@FloatRange(from = 0, to = 1) float value) {
- mTarget.mSaturationTargets[INDEX_MIN] = value;
+ /** Set the minimum chroma value for this target. */
+ @NonNull
+ public Builder setMinimumChroma(@FloatRange(from = 0, to = 100) float value) {
+ mTarget.mChromaMin = value;
return this;
}
- /**
- * Set the target/ideal saturation value for this target.
- */
- public Target.Builder setTargetSaturation(@FloatRange(from = 0, to = 1) float value) {
- mTarget.mSaturationTargets[INDEX_TARGET] = value;
+ /** Set the target/ideal chroma value for this target. */
+ @NonNull
+ public Builder setTargetChroma(@FloatRange(from = 0, to = 100) float value) {
+ mTarget.mChromaTarget = value;
return this;
}
- /**
- * Set the maximum saturation value for this target.
- */
- public Target.Builder setMaximumSaturation(@FloatRange(from = 0, to = 1) float value) {
- mTarget.mSaturationTargets[INDEX_MAX] = value;
+ /** Set the maximum chroma value for this target. */
+ @NonNull
+ public Builder setMaximumChroma(@FloatRange(from = 0, to = 100) float value) {
+ mTarget.mChromaMax = value;
return this;
}
- /**
- * Set the minimum lightness value for this target.
- */
- public Target.Builder setMinimumLightness(@FloatRange(from = 0, to = 1) float value) {
- mTarget.mLightnessTargets[INDEX_MIN] = value;
+ /** Set the minimum lightness value for this target, using Y in XYZ color space. */
+ @NonNull
+ public Builder setTargetRelativeLuminance(@FloatRange(from = 0, to = 100) float value) {
+ mTarget.mTargetRelativeLuminance = value;
return this;
}
- /**
- * Set the target/ideal lightness value for this target.
- */
- public Target.Builder setTargetLightness(@FloatRange(from = 0, to = 1) float value) {
- mTarget.mLightnessTargets[INDEX_TARGET] = value;
+ /** Set the minimum lightness value for this target, using L* in LAB color space. */
+ @NonNull
+ public Builder setTargetPerceptualLuminance(@FloatRange(from = 0, to = 100) float value) {
+ mTarget.mTargetRelativeLuminance = Contrast.lstarToY(value);
return this;
}
/**
- * Set the maximum lightness value for this target.
+ * Set the hue desired from the target. This hue is not enforced, the only consequence
+ * is points will be awarded to seed colors the closer they are to this hue.
*/
- public Target.Builder setMaximumLightness(@FloatRange(from = 0, to = 1) float value) {
- mTarget.mLightnessTargets[INDEX_MAX] = value;
+ @NonNull
+ public Builder setTargetHue(@IntRange(from = 0, to = 360) int hue) {
+ mTarget.mTargetHue = hue;
+ return this;
+ }
+
+ /** Sets lightness value for this target. */
+ @NonNull
+ public Builder setContrastRatio(
+ @FloatRange(from = 1, to = 21) float value,
+ @FloatRange(from = 0, to = 100) float relativeLuminance) {
+ float counterpartY = relativeLuminance;
+ float lstar = Contrast.yToLstar(counterpartY);
+
+ float targetY;
+ if (lstar < 50) {
+ targetY = Contrast.lighterY(counterpartY, value);
+ } else {
+ targetY = Contrast.darkerY(counterpartY, value);
+ }
+ mTarget.mTargetRelativeLuminance = targetY;
return this;
}
/**
- * Set the weight of importance that this target will place on saturation values.
+ * Set the weight of importance that this target will place on chroma values.
*
* <p>The larger the weight, relative to the other weights, the more important that a color
- * being close to the target value has on selection.</p>
+ * being close to the target value has on selection.
*
- * <p>A weight of 0 means that it has no weight, and thus has no
- * bearing on the selection.</p>
+ * <p>A weight of 0 means that it has no weight, and thus has no bearing on the selection.
*
- * @see #setTargetSaturation(float)
+ * @see #setTargetChroma(float)
*/
- public Target.Builder setSaturationWeight(@FloatRange(from = 0) float weight) {
- mTarget.mWeights[INDEX_WEIGHT_SAT] = weight;
+ @NonNull
+ public Builder setChromaWeight(@FloatRange(from = 0) float weight) {
+ mTarget.mChromaWeight = weight;
return this;
}
@@ -385,51 +251,40 @@ public final class Target {
* Set the weight of importance that this target will place on lightness values.
*
* <p>The larger the weight, relative to the other weights, the more important that a color
- * being close to the target value has on selection.</p>
+ * being close to the target value has on selection.
*
- * <p>A weight of 0 means that it has no weight, and thus has no
- * bearing on the selection.</p>
+ * <p>A weight of 0 means that it has no weight, and thus has no bearing on the selection.
*
- * @see #setTargetLightness(float)
+ * @see #setTargetRelativeLuminance(float)
*/
- public Target.Builder setLightnessWeight(@FloatRange(from = 0) float weight) {
- mTarget.mWeights[INDEX_WEIGHT_LUMA] = weight;
+ @NonNull
+ public Builder setLightnessWeight(@FloatRange(from = 0) float weight) {
+ mTarget.mRelativeLuminanceWeight = weight;
return this;
}
/**
* Set the weight of importance that this target will place on a color's population within
- * the image.
+ * the
+ * image.
*
* <p>The larger the weight, relative to the other weights, the more important that a
- * color's population being close to the most populous has on selection.</p>
+ * color's
+ * population being close to the most populous has on selection.
*
- * <p>A weight of 0 means that it has no weight, and thus has no
- * bearing on the selection.</p>
+ * <p>A weight of 0 means that it has no weight, and thus has no bearing on the selection.
*/
- public Target.Builder setPopulationWeight(@FloatRange(from = 0) float weight) {
- mTarget.mWeights[INDEX_WEIGHT_POP] = weight;
+ @NonNull
+ public Builder setPopulationWeight(@FloatRange(from = 0) float weight) {
+ mTarget.mPopulationWeight = weight;
return this;
}
- /**
- * Set whether any color selected for this target is exclusive to this target only.
- * Defaults to true.
- *
- * @param exclusive true if any the color is exclusive to this target, or false is the
- * color can be selected for other targets.
- */
- public Target.Builder setExclusive(boolean exclusive) {
- mTarget.mIsExclusive = exclusive;
- return this;
- }
- /**
- * Builds and returns the resulting {@link Target}.
- */
+ /** Builds and returns the resulting {@link Target}. */
+ @NonNull
public Target build() {
return mTarget;
}
}
-
-} \ No newline at end of file
+}
diff --git a/core/java/com/android/internal/graphics/palette/VariationalKMeansQuantizer.java b/core/java/com/android/internal/graphics/palette/VariationalKMeansQuantizer.java
index b0355350dc15..d791f7b3e6be 100644
--- a/core/java/com/android/internal/graphics/palette/VariationalKMeansQuantizer.java
+++ b/core/java/com/android/internal/graphics/palette/VariationalKMeansQuantizer.java
@@ -70,10 +70,9 @@ public class VariationalKMeansQuantizer implements Quantizer {
*
* @param pixels Pixels to quantize.
* @param maxColors Maximum number of clusters to extract.
- * @param filters Colors that should be ignored
*/
@Override
- public void quantize(int[] pixels, int maxColors, Palette.Filter[] filters) {
+ public void quantize(int[] pixels, int maxColors) {
// Start by converting all colors to HSL.
// HLS is way more meaningful for clustering than RGB.
final float[] hsl = {0, 0, 0};
@@ -111,16 +110,18 @@ public class VariationalKMeansQuantizer implements Quantizer {
// Convert data to final format, de-normalizing the hue.
mQuantizedColors = new ArrayList<>();
+ float[] mHsl = new float[3];
for (KMeans.Mean mean : optimalMeans) {
if (mean.getItems().size() == 0) {
continue;
}
float[] centroid = mean.getCentroid();
- mQuantizedColors.add(new Palette.Swatch(new float[]{
- centroid[0] * 360f,
- centroid[1],
- centroid[2]
- }, mean.getItems().size()));
+
+ mHsl[0] = centroid[0] * 360f;
+ mHsl[1] = centroid[1];
+ mHsl[2] = centroid[2];
+ int color = ColorUtils.HSLToColor(mHsl);
+ mQuantizedColors.add(new Palette.Swatch(color, mean.getItems().size()));
}
}
diff --git a/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java
new file mode 100644
index 000000000000..a87a34f4ae11
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.graphics.palette;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * A color quantizer based on the Kmeans algorithm.
+ *
+ * This is an implementation of Kmeans based on Celebi's 2011 paper,
+ * "Improving the Performance of K-Means for Color Quantization". In the paper, this algorithm is
+ * referred to as "WSMeans", or, "Weighted Square Means" The main advantages of this Kmeans
+ * implementation are taking advantage of triangle properties to avoid distance calculations, as
+ * well as indexing colors by their count, thus minimizing the number of points to move around.
+ *
+ * Celebi's paper also stabilizes results and guarantees high quality by using starting centroids
+ * from Wu's quantization algorithm. See CelebiQuantizer for more info.
+ */
+public class WSMeansQuantizer implements Quantizer {
+ Mean[] mMeans;
+ private final Map<Integer, Integer> mCountByColor = new HashMap<>();
+ private final Map<Integer, Integer> mMeanIndexByColor = new HashMap<>();
+ private final Set<Integer> mUniqueColors = new HashSet<>();
+ private final List<Palette.Swatch> mSwatches = new ArrayList<>();
+ private final CentroidProvider mCentroidProvider;
+
+ public WSMeansQuantizer(
+ float[][] means, CentroidProvider centroidProvider, int[] pixels, int maxColors) {
+ if (pixels == null) {
+ pixels = new int[]{};
+ }
+ mCentroidProvider = centroidProvider;
+ mMeans = new Mean[maxColors];
+ for (int i = 0; i < means.length; i++) {
+ mMeans[i] = new Mean(means[i]);
+ }
+
+ if (maxColors > means.length) {
+ int randomMeansToCreate = maxColors - means.length;
+ for (int i = 0; i < randomMeansToCreate; i++) {
+ mMeans[means.length + i] = new Mean(100);
+ }
+ }
+
+ for (int pixel : pixels) {
+ Integer currentCount = mCountByColor.get(pixel);
+ if (currentCount == null) {
+ currentCount = 0;
+ mUniqueColors.add(pixel);
+ }
+ mCountByColor.put(pixel, currentCount + 1);
+ }
+ for (int color : mUniqueColors) {
+ int closestMeanIndex = -1;
+ double closestMeanDistance = -1;
+ float[] centroid = mCentroidProvider.getCentroid(color);
+ for (int i = 0; i < mMeans.length; i++) {
+ double distance = mCentroidProvider.distance(centroid, mMeans[i].center);
+ if (closestMeanIndex == -1 || distance < closestMeanDistance) {
+ closestMeanIndex = i;
+ closestMeanDistance = distance;
+ }
+ }
+ mMeanIndexByColor.put(color, closestMeanIndex);
+ }
+
+ if (pixels.length == 0) {
+ return;
+ }
+
+ predict(maxColors, 0);
+ }
+
+ /** Create starting centroids for K-means from a set of colors. */
+ public static float[][] createStartingCentroids(CentroidProvider centroidProvider,
+ List<Palette.Swatch> swatches) {
+ float[][] startingCentroids = new float[swatches.size()][];
+ for (int i = 0; i < swatches.size(); i++) {
+ startingCentroids[i] = centroidProvider.getCentroid(swatches.get(i).getInt());
+ }
+ return startingCentroids;
+ }
+
+ /** Create random starting centroids for K-means. */
+ public static float[][] randomMeans(int maxColors, int upperBound) {
+ float[][] means = new float[maxColors][];
+ for (int i = 0; i < maxColors; i++) {
+ means[i] = new Mean(upperBound).center;
+ }
+ return means;
+ }
+
+
+ @Override
+ public void quantize(int[] pixels, int maxColors) {
+
+ }
+
+ @Override
+ public List<Palette.Swatch> getQuantizedColors() {
+ return mSwatches;
+ }
+
+ private void predict(int maxColors, int iterationsCompleted) {
+ double[][] centroidDistance = new double[maxColors][maxColors];
+ for (int i = 0; i <= maxColors; i++) {
+ for (int j = i + 1; j < maxColors; j++) {
+ float[] meanI = mMeans[i].center;
+ float[] meanJ = mMeans[j].center;
+ double distance = mCentroidProvider.distance(meanI, meanJ);
+ centroidDistance[i][j] = distance;
+ centroidDistance[j][i] = distance;
+ }
+ }
+
+ // Construct a K×K matrix M in which row i is a permutation of
+ // 1,2,…,K that represents the clusters in increasing order of
+ // distance of their centers from ci;
+ int[][] distanceMatrix = new int[maxColors][maxColors];
+ for (int i = 0; i < maxColors; i++) {
+ double[] distancesFromIToAnotherMean = centroidDistance[i];
+ double[] sortedByDistanceAscending = distancesFromIToAnotherMean.clone();
+ Arrays.sort(sortedByDistanceAscending);
+ int[] outputRow = new int[maxColors];
+ for (int j = 0; j < maxColors; j++) {
+ outputRow[j] = findIndex(distancesFromIToAnotherMean, sortedByDistanceAscending[j]);
+ }
+ distanceMatrix[i] = outputRow;
+ }
+
+ // for (i=1;i≤N′;i=i+ 1) do
+ // Let Sp be the cluster that xi was assigned to in the previous
+ // iteration;
+ // p=m[i];
+ // min_dist=prev_dist=jjxi−cpjj2;
+ boolean anyColorMoved = false;
+ for (int intColor : mUniqueColors) {
+ float[] color = mCentroidProvider.getCentroid(intColor);
+ int indexOfCurrentMean = mMeanIndexByColor.get(intColor);
+ Mean currentMean = mMeans[indexOfCurrentMean];
+ double minDistance = mCentroidProvider.distance(color, currentMean.center);
+ for (int j = 1; j < maxColors; j++) {
+ int indexOfClusterFromCurrentToJ = distanceMatrix[indexOfCurrentMean][j];
+ double distanceBetweenJAndCurrent =
+ centroidDistance[indexOfCurrentMean][indexOfClusterFromCurrentToJ];
+ if (distanceBetweenJAndCurrent >= (4 * minDistance)) {
+ break;
+ }
+ double distanceBetweenJAndColor = mCentroidProvider.distance(mMeans[j].center,
+ color);
+ if (distanceBetweenJAndColor < minDistance) {
+ minDistance = distanceBetweenJAndColor;
+ mMeanIndexByColor.remove(intColor);
+ mMeanIndexByColor.put(intColor, j);
+ anyColorMoved = true;
+ }
+ }
+ }
+
+ List<MeanBucket> buckets = new ArrayList<>();
+ for (int i = 0; i < maxColors; i++) {
+ buckets.add(new MeanBucket());
+ }
+
+ for (int intColor : mUniqueColors) {
+ int meanIndex = mMeanIndexByColor.get(intColor);
+ MeanBucket meanBucket = buckets.get(meanIndex);
+ meanBucket.add(mCentroidProvider.getCentroid(intColor), intColor,
+ mCountByColor.get(intColor));
+ }
+
+ List<Palette.Swatch> swatches = new ArrayList<>();
+ boolean done = !anyColorMoved && iterationsCompleted > 0 || iterationsCompleted >= 100;
+ if (done) {
+ for (int i = 0; i < buckets.size(); i++) {
+ MeanBucket a = buckets.get(i);
+ if (a.mCount <= 0) {
+ continue;
+ }
+ List<MeanBucket> bucketsToMerge = new ArrayList<>();
+ for (int j = i + 1; j < buckets.size(); j++) {
+ MeanBucket b = buckets.get(j);
+ if (b.mCount == 0) {
+ continue;
+ }
+ float[] bCentroid = b.getCentroid();
+ assert (a.mCount > 0);
+ assert (a.getCentroid() != null);
+
+ assert (bCentroid != null);
+ if (mCentroidProvider.distance(a.getCentroid(), b.getCentroid()) < 5) {
+ bucketsToMerge.add(b);
+ }
+ }
+
+ for (MeanBucket bucketToMerge : bucketsToMerge) {
+ float[] centroid = bucketToMerge.getCentroid();
+ a.add(centroid, mCentroidProvider.getColor(centroid), bucketToMerge.mCount);
+ buckets.remove(bucketToMerge);
+ }
+ }
+
+ for (MeanBucket bucket : buckets) {
+ float[] centroid = bucket.getCentroid();
+ if (centroid == null) {
+ continue;
+ }
+
+ int rgb = mCentroidProvider.getColor(centroid);
+ swatches.add(new Palette.Swatch(rgb, bucket.mCount));
+ mSwatches.clear();
+ mSwatches.addAll(swatches);
+ }
+ } else {
+ List<MeanBucket> emptyBuckets = new ArrayList<>();
+ for (int i = 0; i < buckets.size(); i++) {
+ MeanBucket bucket = buckets.get(i);
+ if ((bucket.getCentroid() == null) || (bucket.mCount == 0)) {
+ emptyBuckets.add(bucket);
+ for (Integer color : mUniqueColors) {
+ int meanIndex = mMeanIndexByColor.get(color);
+ if (meanIndex > i) {
+ mMeanIndexByColor.put(color, meanIndex--);
+ }
+ }
+ }
+ }
+
+ Mean[] newMeans = new Mean[buckets.size()];
+ for (int i = 0; i < buckets.size(); i++) {
+ float[] centroid = buckets.get(i).getCentroid();
+ newMeans[i] = new Mean(centroid);
+ }
+
+ predict(buckets.size(), iterationsCompleted + 1);
+ }
+
+ }
+
+ private static int findIndex(double[] list, double element) {
+ for (int i = 0; i < list.length; i++) {
+ if (list[i] == element) {
+ return i;
+ }
+ }
+ throw new IllegalArgumentException("Element not in list");
+ }
+}
diff --git a/core/java/com/android/internal/graphics/palette/WuQuantizer.java b/core/java/com/android/internal/graphics/palette/WuQuantizer.java
new file mode 100644
index 000000000000..01e45f613986
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/WuQuantizer.java
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.graphics.palette;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+// All reference Wu implementations are based on the original C code by Wu.
+// Comments on methods are the same as in the original implementation, and the comment below
+// is the original class header.
+
+/**
+ * Wu's Color Quantizer (v. 2) (see Graphics Gems vol. II, pp. 126-133) Author: Xiaolin Wu
+ *
+ * <p>Algorithm: Greedy orthogonal bipartition of RGB space for variance minimization aided by
+ * inclusion-exclusion tricks. For speed no nearest neighbor search is done. Slightly better
+ * performance can be expected by more sophisticated but more expensive versions.
+ */
+public class WuQuantizer implements Quantizer {
+ private static final int MAX_COLORS = 256;
+ private static final int RED = 2;
+ private static final int GREEN = 1;
+ private static final int BLUE = 0;
+
+ private static final int QUANT_SIZE = 33;
+ private final List<Palette.Swatch> mSwatches = new ArrayList<>();
+
+ @Override
+ public List<Palette.Swatch> getQuantizedColors() {
+ return mSwatches;
+ }
+
+ private static final class Box {
+ int mR0; /* min value, exclusive */
+ int mR1; /* max value, inclusive */
+ int mG0;
+ int mG1;
+ int mB0;
+ int mB1;
+ int mVol;
+ }
+
+ private final int mSize; /* image size, in bytes. */
+ private int mMaxColors;
+ private int[] mQadd;
+ private final int[] mPixels;
+
+ private final double[][][] mM2 = new double[QUANT_SIZE][QUANT_SIZE][QUANT_SIZE];
+ private final long[][][] mWt = new long[QUANT_SIZE][QUANT_SIZE][QUANT_SIZE];
+ private final long[][][] mMr = new long[QUANT_SIZE][QUANT_SIZE][QUANT_SIZE];
+ private final long[][][] mMg = new long[QUANT_SIZE][QUANT_SIZE][QUANT_SIZE];
+ private final long[][][] mMb = new long[QUANT_SIZE][QUANT_SIZE][QUANT_SIZE];
+
+ public WuQuantizer(int[] pixels, int maxColorCount) {
+ if (pixels == null) {
+ pixels = new int[]{};
+ }
+ this.mPixels = pixels;
+ this.mSize = pixels.length;
+ }
+
+ @Override
+ public void quantize(int[] colors, int maxColorCount) {
+ // All of the sample Wu implementations are reimplementations of a snippet of C code from
+ // the early 90s. They all cap the maximum # of colors at 256, and it is impossible to tell
+ // if this is a requirement, a consequence of QUANT_SIZE, or arbitrary.
+ this.mMaxColors = Math.min(MAX_COLORS, maxColorCount);
+ Box[] cube = new Box[mMaxColors];
+ int red, green, blue;
+
+ int next, i, k;
+ long weight;
+ double[] vv = new double[mMaxColors];
+ double temp;
+
+ compute3DHistogram(mWt, mMr, mMg, mMb, mM2);
+ computeMoments(mWt, mMr, mMg, mMb, mM2);
+
+ for (i = 0; i < mMaxColors; i++) {
+ cube[i] = new Box();
+ }
+
+ cube[0].mR0 = cube[0].mG0 = cube[0].mB0 = 0;
+ cube[0].mR1 = cube[0].mG1 = cube[0].mB1 = QUANT_SIZE - 1;
+ next = 0;
+
+ for (i = 1; i < mMaxColors; ++i) {
+ if (cut(cube[next], cube[i])) {
+ vv[next] = (cube[next].mVol > 1) ? getVariance(cube[next]) : 0.0f;
+ vv[i] = (cube[i].mVol > 1) ? getVariance(cube[i]) : 0.0f;
+ } else {
+ vv[next] = 0.0f;
+ i--;
+ }
+ next = 0;
+ temp = vv[0];
+ for (k = 1; k <= i; ++k) {
+ if (vv[k] > temp) {
+ temp = vv[k];
+ next = k;
+ }
+ }
+ if (temp <= 0.0f) {
+ break;
+ }
+ }
+
+ for (k = 0; k < mMaxColors; ++k) {
+ weight = getVolume(cube[k], mWt);
+ if (weight > 0) {
+ red = (int) (getVolume(cube[k], mMr) / weight);
+ green = (int) (getVolume(cube[k], mMg) / weight);
+ blue = (int) (getVolume(cube[k], mMb) / weight);
+ colors[k] = ((red & 0x0ff) << 16) | ((green & 0x0ff) << 8) | (blue & 0x0ff);
+ } else {
+ colors[k] = 0;
+ }
+ }
+
+ int bitsPerPixel = 0;
+ while ((1 << bitsPerPixel) < mMaxColors) {
+ bitsPerPixel++;
+ }
+
+ List<Palette.Swatch> swatches = new ArrayList<>();
+ for (int l = 0; l < k; l++) {
+ int pixel = colors[l];
+ if (pixel == 0) {
+ continue;
+ }
+ swatches.add(new Palette.Swatch(pixel, 0));
+ }
+ mSwatches.clear();
+ mSwatches.addAll(swatches);
+ }
+
+ /* Histogram is in elements 1..HISTSIZE along each axis,
+ * element 0 is for base or marginal value
+ * NB: these must start out 0!
+ */
+ private void compute3DHistogram(
+ long[][][] vwt, long[][][] vmr, long[][][] vmg, long[][][] vmb, double[][][] m2) {
+ // build 3-D color histogram of counts, r/g/b, and c^2
+ int r, g, b;
+ int i;
+ int inr;
+ int ing;
+ int inb;
+ int[] table = new int[256];
+
+ for (i = 0; i < 256; i++) {
+ table[i] = i * i;
+ }
+
+ mQadd = new int[mSize];
+
+ for (i = 0; i < mSize; ++i) {
+ int rgb = mPixels[i];
+ // Skip less than opaque pixels. They're not meaningful in the context of palette
+ // generation for UI schemes.
+ if ((rgb >>> 24) < 0xff) {
+ continue;
+ }
+ r = ((rgb >> 16) & 0xff);
+ g = ((rgb >> 8) & 0xff);
+ b = (rgb & 0xff);
+ inr = (r >> 3) + 1;
+ ing = (g >> 3) + 1;
+ inb = (b >> 3) + 1;
+ mQadd[i] = (inr << 10) + (inr << 6) + inr + (ing << 5) + ing + inb;
+ /*[inr][ing][inb]*/
+ ++vwt[inr][ing][inb];
+ vmr[inr][ing][inb] += r;
+ vmg[inr][ing][inb] += g;
+ vmb[inr][ing][inb] += b;
+ m2[inr][ing][inb] += table[r] + table[g] + table[b];
+ }
+ }
+
+ /* At conclusion of the histogram step, we can interpret
+ * wt[r][g][b] = sum over voxel of P(c)
+ * mr[r][g][b] = sum over voxel of r*P(c) , similarly for mg, mb
+ * m2[r][g][b] = sum over voxel of c^2*P(c)
+ * Actually each of these should be divided by 'size' to give the usual
+ * interpretation of P() as ranging from 0 to 1, but we needn't do that here.
+ *
+ * We now convert histogram into moments so that we can rapidly calculate
+ * the sums of the above quantities over any desired box.
+ */
+ private void computeMoments(
+ long[][][] vwt, long[][][] vmr, long[][][] vmg, long[][][] vmb, double[][][] m2) {
+ /* compute cumulative moments. */
+ int i, r, g, b;
+ int line, line_r, line_g, line_b;
+ int[] area = new int[QUANT_SIZE];
+ int[] area_r = new int[QUANT_SIZE];
+ int[] area_g = new int[QUANT_SIZE];
+ int[] area_b = new int[QUANT_SIZE];
+ double line2;
+ double[] area2 = new double[QUANT_SIZE];
+
+ for (r = 1; r < QUANT_SIZE; ++r) {
+ for (i = 0; i < QUANT_SIZE; ++i) {
+ area2[i] = area[i] = area_r[i] = area_g[i] = area_b[i] = 0;
+ }
+ for (g = 1; g < QUANT_SIZE; ++g) {
+ line2 = line = line_r = line_g = line_b = 0;
+ for (b = 1; b < QUANT_SIZE; ++b) {
+ line += vwt[r][g][b];
+ line_r += vmr[r][g][b];
+ line_g += vmg[r][g][b];
+ line_b += vmb[r][g][b];
+ line2 += m2[r][g][b];
+
+ area[b] += line;
+ area_r[b] += line_r;
+ area_g[b] += line_g;
+ area_b[b] += line_b;
+ area2[b] += line2;
+
+ vwt[r][g][b] = vwt[r - 1][g][b] + area[b];
+ vmr[r][g][b] = vmr[r - 1][g][b] + area_r[b];
+ vmg[r][g][b] = vmg[r - 1][g][b] + area_g[b];
+ vmb[r][g][b] = vmb[r - 1][g][b] + area_b[b];
+ m2[r][g][b] = m2[r - 1][g][b] + area2[b];
+ }
+ }
+ }
+ }
+
+ private long getVolume(Box cube, long[][][] mmt) {
+ /* Compute sum over a box of any given statistic */
+ return (mmt[cube.mR1][cube.mG1][cube.mB1]
+ - mmt[cube.mR1][cube.mG1][cube.mB0]
+ - mmt[cube.mR1][cube.mG0][cube.mB1]
+ + mmt[cube.mR1][cube.mG0][cube.mB0]
+ - mmt[cube.mR0][cube.mG1][cube.mB1]
+ + mmt[cube.mR0][cube.mG1][cube.mB0]
+ + mmt[cube.mR0][cube.mG0][cube.mB1]
+ - mmt[cube.mR0][cube.mG0][cube.mB0]);
+ }
+
+ /* The next two routines allow a slightly more efficient calculation
+ * of Vol() for a proposed subbox of a given box. The sum of Top()
+ * and Bottom() is the Vol() of a subbox split in the given direction
+ * and with the specified new upper bound.
+ */
+ private long getBottom(Box cube, int dir, long[][][] mmt) {
+ /* Compute part of Vol(cube, mmt) that doesn't depend on r1, g1, or b1 */
+ /* (depending on dir) */
+ switch (dir) {
+ case RED:
+ return (-mmt[cube.mR0][cube.mG1][cube.mB1]
+ + mmt[cube.mR0][cube.mG1][cube.mB0]
+ + mmt[cube.mR0][cube.mG0][cube.mB1]
+ - mmt[cube.mR0][cube.mG0][cube.mB0]);
+ case GREEN:
+ return (-mmt[cube.mR1][cube.mG0][cube.mB1]
+ + mmt[cube.mR1][cube.mG0][cube.mB0]
+ + mmt[cube.mR0][cube.mG0][cube.mB1]
+ - mmt[cube.mR0][cube.mG0][cube.mB0]);
+ case BLUE:
+ return (-mmt[cube.mR1][cube.mG1][cube.mB0]
+ + mmt[cube.mR1][cube.mG0][cube.mB0]
+ + mmt[cube.mR0][cube.mG1][cube.mB0]
+ - mmt[cube.mR0][cube.mG0][cube.mB0]);
+ default:
+ return 0;
+ }
+ }
+
+ private long getTop(Box cube, int dir, int pos, long[][][] mmt) {
+ /* Compute remainder of Vol(cube, mmt), substituting pos for */
+ /* r1, g1, or b1 (depending on dir) */
+ switch (dir) {
+ case RED:
+ return (mmt[pos][cube.mG1][cube.mB1]
+ - mmt[pos][cube.mG1][cube.mB0]
+ - mmt[pos][cube.mG0][cube.mB1]
+ + mmt[pos][cube.mG0][cube.mB0]);
+ case GREEN:
+ return (mmt[cube.mR1][pos][cube.mB1]
+ - mmt[cube.mR1][pos][cube.mB0]
+ - mmt[cube.mR0][pos][cube.mB1]
+ + mmt[cube.mR0][pos][cube.mB0]);
+ case BLUE:
+ return (mmt[cube.mR1][cube.mG1][pos]
+ - mmt[cube.mR1][cube.mG0][pos]
+ - mmt[cube.mR0][cube.mG1][pos]
+ + mmt[cube.mR0][cube.mG0][pos]);
+ default:
+ return 0;
+ }
+ }
+
+ private double getVariance(Box cube) {
+ /* Compute the weighted variance of a box */
+ /* NB: as with the raw statistics, this is really the variance * size */
+ double dr, dg, db, xx;
+ dr = getVolume(cube, mMr);
+ dg = getVolume(cube, mMg);
+ db = getVolume(cube, mMb);
+ xx =
+ mM2[cube.mR1][cube.mG1][cube.mB1]
+ - mM2[cube.mR1][cube.mG1][cube.mB0]
+ - mM2[cube.mR1][cube.mG0][cube.mB1]
+ + mM2[cube.mR1][cube.mG0][cube.mB0]
+ - mM2[cube.mR0][cube.mG1][cube.mB1]
+ + mM2[cube.mR0][cube.mG1][cube.mB0]
+ + mM2[cube.mR0][cube.mG0][cube.mB1]
+ - mM2[cube.mR0][cube.mG0][cube.mB0];
+ return xx - (dr * dr + dg * dg + db * db) / getVolume(cube, mWt);
+ }
+
+ /* We want to minimize the sum of the variances of two subboxes.
+ * The sum(c^2) terms can be ignored since their sum over both subboxes
+ * is the same (the sum for the whole box) no matter where we split.
+ * The remaining terms have a minus sign in the variance formula,
+ * so we drop the minus sign and MAXIMIZE the sum of the two terms.
+ */
+ private double maximize(
+ Box cube,
+ int dir,
+ int first,
+ int last,
+ int[] cut,
+ long wholeR,
+ long wholeG,
+ long wholeB,
+ long wholeW) {
+ long half_r, half_g, half_b, half_w;
+ long base_r, base_g, base_b, base_w;
+ int i;
+ double temp, max;
+
+ base_r = getBottom(cube, dir, mMr);
+ base_g = getBottom(cube, dir, mMg);
+ base_b = getBottom(cube, dir, mMb);
+ base_w = getBottom(cube, dir, mWt);
+
+ max = 0.0f;
+ cut[0] = -1;
+
+ for (i = first; i < last; ++i) {
+ half_r = base_r + getTop(cube, dir, i, mMr);
+ half_g = base_g + getTop(cube, dir, i, mMg);
+ half_b = base_b + getTop(cube, dir, i, mMb);
+ half_w = base_w + getTop(cube, dir, i, mWt);
+ /* now half_x is sum over lower half of box, if split at i */
+ if (half_w == 0) /* subbox could be empty of pixels! */ {
+ continue; /* never split into an empty box */
+ }
+ temp = (half_r * half_r + half_g * half_g + half_b * half_b) / (double) half_w;
+ half_r = wholeR - half_r;
+ half_g = wholeG - half_g;
+ half_b = wholeB - half_b;
+ half_w = wholeW - half_w;
+ if (half_w == 0) /* subbox could be empty of pixels! */ {
+ continue; /* never split into an empty box */
+ }
+ temp += (half_r * half_r + half_g * half_g + half_b * half_b) / (double) half_w;
+
+ if (temp > max) {
+ max = temp;
+ cut[0] = i;
+ }
+ }
+
+ return max;
+ }
+
+ private boolean cut(Box set1, Box set2) {
+ int dir;
+ int[] cutr = new int[1];
+ int[] cutg = new int[1];
+ int[] cutb = new int[1];
+ double maxr, maxg, maxb;
+ long whole_r, whole_g, whole_b, whole_w;
+
+ whole_r = getVolume(set1, mMr);
+ whole_g = getVolume(set1, mMg);
+ whole_b = getVolume(set1, mMb);
+ whole_w = getVolume(set1, mWt);
+
+ maxr = maximize(set1, RED, set1.mR0 + 1, set1.mR1, cutr, whole_r, whole_g, whole_b,
+ whole_w);
+ maxg = maximize(set1, GREEN, set1.mG0 + 1, set1.mG1, cutg, whole_r, whole_g, whole_b,
+ whole_w);
+ maxb = maximize(set1, BLUE, set1.mB0 + 1, set1.mB1, cutb, whole_r, whole_g, whole_b,
+ whole_w);
+
+ if (maxr >= maxg && maxr >= maxb) {
+ dir = RED;
+ if (cutr[0] < 0) return false; /* can't split the box */
+ } else if (maxg >= maxr && maxg >= maxb) {
+ dir = GREEN;
+ } else {
+ dir = BLUE;
+ }
+
+ set2.mR1 = set1.mR1;
+ set2.mG1 = set1.mG1;
+ set2.mB1 = set1.mB1;
+
+ switch (dir) {
+ case RED:
+ set2.mR0 = set1.mR1 = cutr[0];
+ set2.mG0 = set1.mG0;
+ set2.mB0 = set1.mB0;
+ break;
+ case GREEN:
+ set2.mG0 = set1.mG1 = cutg[0];
+ set2.mR0 = set1.mR0;
+ set2.mB0 = set1.mB0;
+ break;
+ case BLUE:
+ set2.mB0 = set1.mB1 = cutb[0];
+ set2.mR0 = set1.mR0;
+ set2.mG0 = set1.mG0;
+ break;
+ }
+ set1.mVol = (set1.mR1 - set1.mR0) * (set1.mG1 - set1.mG0) * (set1.mB1 - set1.mB0);
+ set2.mVol = (set2.mR1 - set2.mR0) * (set2.mG1 - set2.mG0) * (set2.mB1 - set2.mB0);
+
+ return true;
+ }
+}
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index e82cc737a395..342456a58091 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -25,6 +25,9 @@ import static android.view.SurfaceControl.JankData.JANK_SURFACEFLINGER_GPU_DEADL
import static android.view.SurfaceControl.JankData.PREDICTION_ERROR;
import static android.view.SurfaceControl.JankData.SURFACE_FLINGER_SCHEDULING;
+import static com.android.internal.jank.InteractionJankMonitor.ACTION_METRICS_LOGGED;
+import static com.android.internal.jank.InteractionJankMonitor.ACTION_SESSION_BEGIN;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.HardwareRendererObserver;
@@ -72,6 +75,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
private long mEndVsyncId = INVALID_ID;
private boolean mMetricsFinalized;
private boolean mCancelled = false;
+ private FrameTrackerListener mListener;
private static class JankInfo {
long frameVsyncId;
@@ -109,7 +113,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
@NonNull SurfaceControlWrapper surfaceControlWrapper,
@NonNull ChoreographerWrapper choreographer,
@NonNull FrameMetricsWrapper metrics, int traceThresholdMissedFrames,
- int traceThresholdFrameTimeMillis) {
+ int traceThresholdFrameTimeMillis, @Nullable FrameTrackerListener listener) {
mSession = session;
mRendererWrapper = renderer;
mMetricsWrapper = metrics;
@@ -120,6 +124,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
mObserver = new HardwareRendererObserver(this, mMetricsWrapper.getTiming(), handler);
mTraceThresholdMissedFrames = traceThresholdMissedFrames;
mTraceThresholdFrameTimeMillis = traceThresholdFrameTimeMillis;
+ mListener = listener;
// If the surface isn't valid yet, wait until it's created.
if (viewRootWrapper.getSurfaceControl().isValid()) {
@@ -165,11 +170,15 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
*/
public synchronized void begin() {
mBeginVsyncId = mChoreographer.getVsyncId() + 1;
+ mSession.setTimeStamp(System.nanoTime());
Trace.beginAsyncSection(mSession.getName(), (int) mBeginVsyncId);
mRendererWrapper.addObserver(mObserver);
if (mSurfaceControl != null) {
mSurfaceControlWrapper.addJankStatsListener(this, mSurfaceControl);
}
+ if (mListener != null) {
+ mListener.onNotifyCujEvents(mSession, ACTION_SESSION_BEGIN);
+ }
}
/**
@@ -224,7 +233,6 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
private boolean isInRange(long vsyncId) {
-
// It's possible that we may miss a callback for the frame with vsyncId == mEndVsyncId.
// Because of that, we collect all frames even if they happen after the end so we eventually
// have a frame after the end with both callbacks present.
@@ -371,6 +379,9 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
missedAppFramesCount + missedSfFramesCounts,
maxFrameTimeNanos,
missedSfFramesCounts);
+ if (mListener != null) {
+ mListener.onNotifyCujEvents(mSession, ACTION_METRICS_LOGGED);
+ }
}
if (DEBUG) {
Log.i(TAG, "FrameTracker: CUJ=" + mSession.getName()
@@ -495,4 +506,17 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
return mChoreographer.getVsyncId();
}
}
+
+ /**
+ * A listener that notifies cuj events.
+ */
+ public interface FrameTrackerListener {
+ /**
+ * Notify that the CUJ session was created.
+ *
+ * @param session the CUJ session
+ * @param action the specific action
+ */
+ void onNotifyCujEvents(Session session, String action);
+ }
}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index cba6af98a980..0294ec398484 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -16,6 +16,8 @@
package com.android.internal.jank;
+import static android.content.Intent.FLAG_RECEIVER_REGISTERED_ONLY;
+
import static com.android.internal.jank.FrameTracker.ChoreographerWrapper;
import static com.android.internal.jank.FrameTracker.SurfaceControlWrapper;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL;
@@ -48,9 +50,12 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Intent;
import android.os.Build;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
+import android.os.SystemProperties;
import android.provider.DeviceConfig;
import android.util.Log;
import android.util.SparseArray;
@@ -59,6 +64,7 @@ import android.view.View;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.FrameTracker.FrameMetricsWrapper;
+import com.android.internal.jank.FrameTracker.FrameTrackerListener;
import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper;
import com.android.internal.jank.FrameTracker.ViewRootWrapper;
import com.android.internal.util.PerfettoTrigger;
@@ -74,6 +80,8 @@ import java.util.concurrent.TimeUnit;
*/
public class InteractionJankMonitor {
private static final String TAG = InteractionJankMonitor.class.getSimpleName();
+ private static final String ACTION_PREFIX = InteractionJankMonitor.class.getCanonicalName();
+
private static final String DEFAULT_WORKER_NAME = TAG + "-Worker";
private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5L);
private static final String SETTINGS_ENABLED_KEY = "enabled";
@@ -90,6 +98,14 @@ public class InteractionJankMonitor {
private static final int DEFAULT_TRACE_THRESHOLD_MISSED_FRAMES = 3;
private static final int DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS = 64;
+ public static final String ACTION_SESSION_BEGIN = ACTION_PREFIX + ".ACTION_SESSION_BEGIN";
+ public static final String ACTION_SESSION_END = ACTION_PREFIX + ".ACTION_SESSION_END";
+ public static final String ACTION_METRICS_LOGGED = ACTION_PREFIX + ".ACTION_METRICS_LOGGED";
+ public static final String BUNDLE_KEY_CUJ_NAME = ACTION_PREFIX + ".CUJ_NAME";
+ public static final String BUNDLE_KEY_TIMESTAMP = ACTION_PREFIX + ".TIMESTAMP";
+ @VisibleForTesting
+ public static final String PROP_NOTIFY_CUJ_EVENT = "debug.notify_cuj_events";
+
// Every value must have a corresponding entry in CUJ_STATSD_INTERACTION_TYPE.
public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE = 0;
public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE_LOCK = 1;
@@ -256,15 +272,28 @@ public class InteractionJankMonitor {
*/
@VisibleForTesting
public FrameTracker createFrameTracker(View v, Session session) {
+ final Context c = v.getContext().getApplicationContext();
synchronized (this) {
+ boolean needListener = SystemProperties.getBoolean(PROP_NOTIFY_CUJ_EVENT, false);
+ FrameTrackerListener eventsListener =
+ !needListener ? null : (s, act) -> notifyEvents(c, act, s);
+
return new FrameTracker(session, mWorker.getThreadHandler(),
new ThreadedRendererWrapper(v.getThreadedRenderer()),
new ViewRootWrapper(v.getViewRootImpl()), new SurfaceControlWrapper(),
new ChoreographerWrapper(Choreographer.getInstance()), mMetrics,
- mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis);
+ mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis, eventsListener);
}
}
+ private void notifyEvents(Context context, String action, Session session) {
+ Intent intent = new Intent(action);
+ intent.putExtra(BUNDLE_KEY_CUJ_NAME, getNameOfCuj(session.getCuj()));
+ intent.putExtra(BUNDLE_KEY_TIMESTAMP, session.getTimeStamp());
+ intent.addFlags(FLAG_RECEIVER_REGISTERED_ONLY);
+ context.sendBroadcast(intent);
+ }
+
/**
* Begin a trace session.
*
@@ -479,6 +508,7 @@ public class InteractionJankMonitor {
public static class Session {
@CujType
private int mCujType;
+ private long mTimeStamp;
public Session(@CujType int cujType) {
mCujType = cujType;
@@ -505,5 +535,13 @@ public class InteractionJankMonitor {
public String getName() {
return "J<" + getNameOfCuj(mCujType) + ">";
}
+
+ public void setTimeStamp(long timeStamp) {
+ mTimeStamp = timeStamp;
+ }
+
+ public long getTimeStamp() {
+ return mTimeStamp;
+ }
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 1f8ffe08a257..54095bd86887 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -12520,6 +12520,7 @@ public class BatteryStatsImpl extends BatteryStats {
* @param totalEnergyUJ energy (microjoules) used for this bucket since this was last called.
* @param uidEnergies map of uid->energy (microjoules) for this bucket since last called.
* Data inside uidEnergies will not be modified (treated immutable).
+ * Uids not already known to BatteryStats will be ignored.
*/
public void updateCustomMeasuredEnergyDataLocked(int customEnergyBucket,
long totalEnergyUJ, @Nullable SparseLongArray uidEnergies) {
@@ -12540,10 +12541,20 @@ public class BatteryStatsImpl extends BatteryStats {
final int uidInt = mapUid(uidEnergies.keyAt(i));
final long uidEnergyUJ = uidEnergies.valueAt(i);
if (uidEnergyUJ == 0) continue;
- // TODO(b/180030409): Worry about dead Uids (no longer in BSI) being revived by this,
- // or converse problem of not creating a new Uid if its first blame is recorded here.
- final Uid uidObj = getUidStatsLocked(uidInt);
- uidObj.addEnergyToCustomBucketLocked(uidEnergyUJ, customEnergyBucket, true);
+ final Uid uidObj = getAvailableUidStatsLocked(uidInt);
+ if (uidObj != null) {
+ uidObj.addEnergyToCustomBucketLocked(uidEnergyUJ, customEnergyBucket, true);
+ } else {
+ // Ignore any uid not already known to BatteryStats, rather than creating a new Uid.
+ // Otherwise we could end up reviving dead Uids. Note that the CPU data is updated
+ // first, so any uid that has used any CPU should already be known to BatteryStats.
+ // Recently removed uids (especially common for isolated uids) can reach this path
+ // and are ignored.
+ if (!Process.isIsolated(uidInt)) {
+ Slog.w(TAG, "Received measured energy " + totalEnergyUJ + " for custom bucket "
+ + customEnergyBucket + " for non-existent uid " + uidInt);
+ }
+ }
}
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index c8afea9b0982..b99c953fa4e8 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -103,7 +103,7 @@ public final class Zygote {
*/
public static final int PROFILE_FROM_SHELL = 1 << 15;
- /**
+ /*
* Enable using the ART app image startup cache
*/
public static final int USE_APP_IMAGE_STARTUP_CACHE = 1 << 16;
@@ -116,6 +116,13 @@ public final class Zygote {
*/
public static final int DEBUG_IGNORE_APP_SIGNAL_HANDLER = 1 << 17;
+ /**
+ * Disable runtime access to {@link android.annotation.TestApi} annotated members.
+ *
+ * <p>This only takes effect if Hidden API access restrictions are enabled as well.
+ */
+ public static final int DISABLE_TEST_API_ENFORCEMENT_POLICY = 1 << 18;
+
public static final int MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20);
public static final int MEMORY_TAG_LEVEL_NONE = 0;
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index 56b25b2060ea..93ba0372df08 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -180,6 +180,7 @@ public class TransitionAnimation {
"android", com.android.internal.R.anim.cross_profile_apps_thumbnail_enter);
}
+ /** Load animation by resource Id from specific LayoutParams. */
@Nullable
private Animation loadAnimationRes(LayoutParams lp, int resId) {
Context context = mContext;
@@ -193,6 +194,7 @@ public class TransitionAnimation {
return null;
}
+ /** Load animation by resource Id from specific package. */
@Nullable
private Animation loadAnimationRes(String packageName, int resId) {
if (ResourceId.isValid(resId)) {
@@ -204,6 +206,13 @@ public class TransitionAnimation {
return null;
}
+ /** Load animation by resource Id from android package. */
+ @Nullable
+ public Animation loadDefaultAnimationRes(int resId) {
+ return loadAnimationRes("android", resId);
+ }
+
+ /** Load animation by attribute Id from specific LayoutParams */
@Nullable
public Animation loadAnimationAttr(LayoutParams lp, int animAttr, int transit) {
int resId = Resources.ID_NULL;
@@ -222,6 +231,25 @@ public class TransitionAnimation {
return null;
}
+ /** Load animation by attribute Id from android package. */
+ @Nullable
+ public Animation loadDefaultAnimationAttr(int animAttr) {
+ int resId = Resources.ID_NULL;
+ Context context = mContext;
+ if (animAttr >= 0) {
+ AttributeCache.Entry ent = getCachedAnimations("android",
+ mDefaultWindowAnimationStyleResId);
+ if (ent != null) {
+ context = ent.context;
+ resId = ent.array.getResourceId(animAttr, 0);
+ }
+ }
+ if (ResourceId.isValid(resId)) {
+ return loadAnimationSafely(context, resId, mTag);
+ }
+ return null;
+ }
+
@Nullable
private AttributeCache.Entry getCachedAnimations(LayoutParams lp) {
if (mDebug) {
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 7edc6c855ec2..fde48e86b0f3 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -67,7 +67,7 @@ interface IStatusBarService
void onNotificationError(String pkg, String tag, int id,
int uid, int initialPid, String message, int userId);
void onClearAllNotifications(int userId);
- void onNotificationClear(String pkg, String tag, int id, int userId, String key,
+ void onNotificationClear(String pkg, int userId, String key,
int dismissalSurface, int dismissalSentiment, in NotificationVisibility nv);
void onNotificationVisibilityChanged( in NotificationVisibility[] newlyVisibleKeys,
in NotificationVisibility[] noLongerVisibleKeys);
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index c33637353984..8d82e33dc29f 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -35,7 +35,8 @@ import com.android.internal.view.InlineSuggestionsRequestInfo;
* {@hide}
*/
oneway interface IInputMethod {
- void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps);
+ void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps,
+ int configChanges);
void onCreateInlineSuggestionsRequest(in InlineSuggestionsRequestInfo requestInfo,
in IInlineSuggestionsRequestCallback cb);
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 8982519eff96..671cb8481dd9 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -1234,10 +1234,10 @@ public class SystemConfig {
addFeature(PackageManager.FEATURE_RAM_NORMAL, 0);
}
- if (IncrementalManager.isFeatureEnabled()) {
+ final int incrementalVersion = IncrementalManager.getVersion();
+ if (incrementalVersion > 0) {
addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY, 0);
- addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY_VERSION,
- IncrementalManager.isV2Available() ? 2 : 1);
+ addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY_VERSION, incrementalVersion);
}
if (PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT) {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index cf8711b3c037..b485f0f4fb62 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -121,6 +121,7 @@ cc_library_shared {
"android_view_PointerIcon.cpp",
"android_view_Surface.cpp",
"android_view_SurfaceControl.cpp",
+ "android_view_SurfaceControlFpsListener.cpp",
"android_graphics_BLASTBufferQueue.cpp",
"android_view_SurfaceSession.cpp",
"android_view_TextureView.cpp",
@@ -175,6 +176,7 @@ cc_library_shared {
"android_hardware_Camera.cpp",
"android_hardware_camera2_CameraMetadata.cpp",
"android_hardware_camera2_DngCreator.cpp",
+ "android_hardware_camera2_impl_CameraExtensionJpegProcessor.cpp",
"android_hardware_camera2_utils_SurfaceUtils.cpp",
"android_hardware_display_DisplayManagerGlobal.cpp",
"android_hardware_display_DisplayViewport.cpp",
@@ -231,6 +233,7 @@ cc_library_shared {
"audioclient-types-aidl-cpp",
"audioflinger-aidl-cpp",
"av-types-aidl-cpp",
+ "android.hardware.camera.device@3.2",
"libandroidicu",
"libbpf_android",
"libnetdbpf",
@@ -260,6 +263,7 @@ cc_library_shared {
"libdataloader",
"libvulkan",
"libETC1",
+ "libjpeg",
"libhardware",
"libhardware_legacy",
"libselinux",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 38bcc0f4c59e..dc77bba44607 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -74,6 +74,7 @@ extern int register_android_opengl_jni_GLES32(JNIEnv* env);
extern int register_android_hardware_Camera(JNIEnv *env);
extern int register_android_hardware_camera2_CameraMetadata(JNIEnv *env);
extern int register_android_hardware_camera2_DngCreator(JNIEnv *env);
+extern int register_android_hardware_camera2_impl_CameraExtensionJpegProcessor(JNIEnv* env);
extern int register_android_hardware_camera2_utils_SurfaceUtils(JNIEnv* env);
extern int register_android_hardware_display_DisplayManagerGlobal(JNIEnv* env);
extern int register_android_hardware_HardwareBuffer(JNIEnv *env);
@@ -119,6 +120,7 @@ extern int register_android_view_InputApplicationHandle(JNIEnv* env);
extern int register_android_view_InputWindowHandle(JNIEnv* env);
extern int register_android_view_Surface(JNIEnv* env);
extern int register_android_view_SurfaceControl(JNIEnv* env);
+extern int register_android_view_SurfaceControlFpsListener(JNIEnv* env);
extern int register_android_view_SurfaceSession(JNIEnv* env);
extern int register_android_view_CompositionSamplingListener(JNIEnv* env);
extern int register_android_view_TextureView(JNIEnv* env);
@@ -1487,6 +1489,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_view_InputWindowHandle),
REG_JNI(register_android_view_Surface),
REG_JNI(register_android_view_SurfaceControl),
+ REG_JNI(register_android_view_SurfaceControlFpsListener),
REG_JNI(register_android_view_SurfaceSession),
REG_JNI(register_android_view_CompositionSamplingListener),
REG_JNI(register_android_view_TextureView),
@@ -1533,6 +1536,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_hardware_Camera),
REG_JNI(register_android_hardware_camera2_CameraMetadata),
REG_JNI(register_android_hardware_camera2_DngCreator),
+ REG_JNI(register_android_hardware_camera2_impl_CameraExtensionJpegProcessor),
REG_JNI(register_android_hardware_camera2_utils_SurfaceUtils),
REG_JNI(register_android_hardware_display_DisplayManagerGlobal),
REG_JNI(register_android_hardware_HardwareBuffer),
diff --git a/core/jni/android_hardware_camera2_impl_CameraExtensionJpegProcessor.cpp b/core/jni/android_hardware_camera2_impl_CameraExtensionJpegProcessor.cpp
new file mode 100644
index 000000000000..139075907bf3
--- /dev/null
+++ b/core/jni/android_hardware_camera2_impl_CameraExtensionJpegProcessor.cpp
@@ -0,0 +1,629 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <array>
+#include <cstring>
+#include <cstdio>
+#include <inttypes.h>
+#include <memory.h>
+#include <vector>
+
+#include <setjmp.h>
+
+#include <android/hardware/camera/device/3.2/types.h>
+
+#include "core_jni_helpers.h"
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+
+#define CAMERA_PROCESSOR_CLASS_NAME "android/hardware/camera2/impl/CameraExtensionJpegProcessor"
+
+extern "C" {
+#include "jpeglib.h"
+}
+
+using namespace std;
+using namespace android;
+
+using android::hardware::camera::device::V3_2::CameraBlob;
+using android::hardware::camera::device::V3_2::CameraBlobId;
+
+class Transform;
+struct Plane;
+
+inline int sgn(int val) { return (0 < val) - (val < 0); }
+
+inline int min(int a, int b) { return a < b ? a : b; }
+
+inline int max(int a, int b) { return a > b ? a : b; }
+
+/**
+ * Represents a combined cropping and rotation transformation.
+ *
+ * The transformation maps the coordinates (mOrigX, mOrigY) and (mOneX, mOneY)
+ * in the input image to the origin and (mOutputWidth, mOutputHeight)
+ * respectively.
+ */
+class Transform {
+ public:
+ Transform(int origX, int origY, int oneX, int oneY);
+
+ static Transform forCropFollowedByRotation(int cropLeft, int cropTop,
+ int cropRight, int cropBottom, int rot90);
+
+ inline int getOutputWidth() const { return mOutputWidth; }
+
+ inline int getOutputHeight() const { return mOutputHeight; }
+
+ bool operator==(const Transform& other) const;
+
+ /**
+ * Transforms the input coordinates. Coordinates outside the cropped region
+ * are clamped to valid values.
+ */
+ void map(int x, int y, int* outX, int* outY) const;
+
+ private:
+ int mOutputWidth;
+ int mOutputHeight;
+
+ // The coordinates of the point to map the origin to.
+ const int mOrigX, mOrigY;
+ // The coordinates of the point to map the point (getOutputWidth(),
+ // getOutputHeight()) to.
+ const int mOneX, mOneY;
+
+ // A matrix for the rotational component.
+ int mMat00, mMat01;
+ int mMat10, mMat11;
+};
+
+/**
+ * Represents a model for accessing pixel data for a single plane of an image.
+ * Note that the actual data is not owned by this class, and the underlying
+ * data does not need to be stored in separate planes.
+ */
+struct Plane {
+ // The dimensions of this plane of the image
+ int width;
+ int height;
+
+ // A pointer to raw pixel data
+ const unsigned char* data;
+ // The difference in address between consecutive pixels in the same row
+ int pixelStride;
+ // The difference in address between the start of consecutive rows
+ int rowStride;
+};
+
+/**
+ * Provides an interface for simultaneously reading a certain number of rows of
+ * an image plane as contiguous arrays, suitable for use with libjpeg.
+ */
+template <unsigned int ROWS>
+class RowIterator {
+ public:
+ /**
+ * Creates a new RowIterator which will crop and rotate with the given
+ * transform.
+ *
+ * @param plane the plane to iterate over
+ * @param transform the transformation to map output values into the
+ * coordinate space of the plane
+ * @param rowLength the length of the rows returned via LoadAt(). If this is
+ * longer than the width of the output (after applying the transform), then
+ * the right-most value is repeated.
+ */
+ inline RowIterator(Plane plane, Transform transform, int rowLength);
+
+ /**
+ * Returns an array of pointers into consecutive rows of contiguous image
+ * data starting at y. That is, samples within each row are contiguous.
+ * However, the individual arrays pointed-to may be separate.
+ * When the end of the image is reached, the last row of the image is
+ * repeated.
+ * The returned pointers are valid until the next call to loadAt().
+ */
+ inline const std::array<unsigned char*, ROWS> loadAt(int baseY);
+
+ private:
+ Plane mPlane;
+ Transform mTransform;
+ // The length of a row, with padding to the next multiple of 64.
+ int mPaddedRowLength;
+ std::vector<unsigned char> mBuffer;
+};
+
+template <unsigned int ROWS>
+RowIterator<ROWS>::RowIterator(Plane plane, Transform transform,
+ int rowLength)
+ : mPlane(plane), mTransform(transform) {
+ mPaddedRowLength = rowLength;
+ mBuffer = std::vector<unsigned char>(rowLength * ROWS);
+}
+
+template <unsigned int ROWS>
+const std::array<unsigned char*, ROWS> RowIterator<ROWS>::loadAt(int baseY) {
+ std::array<unsigned char*, ROWS> bufPtrs;
+ for (unsigned int i = 0; i < ROWS; i++) {
+ bufPtrs[i] = &mBuffer[mPaddedRowLength * i];
+ }
+
+ if (mPlane.width == 0 || mPlane.height == 0) {
+ return bufPtrs;
+ }
+
+ for (unsigned int i = 0; i < ROWS; i++) {
+ int y = i + baseY;
+ y = min(y, mTransform.getOutputHeight() - 1);
+
+ int output_width = mPaddedRowLength;
+ output_width = min(output_width, mTransform.getOutputWidth());
+ output_width = min(output_width, mPlane.width);
+
+ // Each row in the output image will be copied into buf_ by gathering pixels
+ // along an axis-aligned line in the plane.
+ // The line is defined by (startX, startY) -> (endX, endY), computed via the
+ // current Transform.
+ int startX;
+ int startY;
+ mTransform.map(0, y, &startX, &startY);
+
+ int endX;
+ int endY;
+ mTransform.map(output_width - 1, y, &endX, &endY);
+
+ // Clamp (startX, startY) and (endX, endY) to the valid bounds of the plane.
+ startX = min(startX, mPlane.width - 1);
+ startY = min(startY, mPlane.height - 1);
+ endX = min(endX, mPlane.width - 1);
+ endY = min(endY, mPlane.height - 1);
+ startX = max(startX, 0);
+ startY = max(startY, 0);
+ endX = max(endX, 0);
+ endY = max(endY, 0);
+
+ // To reduce work inside the copy-loop, precompute the start, end, and
+ // stride relating the values to be gathered from mPlane into buf
+ // for this particular scan-line.
+ int dx = sgn(endX - startX);
+ int dy = sgn(endY - startY);
+ if (!(dx == 0 || dy == 0)) {
+ ALOGE("%s: Unexpected bounds: %dx%d %dx%d!", __FUNCTION__, startX, endX, startY, endY);
+ return bufPtrs;
+ }
+
+ // The index into mPlane.data of (startX, startY)
+ int plane_start = startX * mPlane.pixelStride + startY * mPlane.rowStride;
+ // The index into mPlane.data of (endX, endY)
+ int plane_end = endX * mPlane.pixelStride + endY * mPlane.rowStride;
+ // The stride, in terms of indices in plane_data, required to enumerate the
+ // samples between the start and end points.
+ int stride = dx * mPlane.pixelStride + dy * mPlane.rowStride;
+ // In the degenerate-case of a 1x1 plane, startX and endX are equal, so
+ // stride would be 0, resulting in an infinite-loop. To avoid this case,
+ // use a stride of at-least 1.
+ if (stride == 0) {
+ stride = 1;
+ }
+
+ int outX = 0;
+ for (int idx = plane_start; idx >= min(plane_start, plane_end) &&
+ idx <= max(plane_start, plane_end); idx += stride) {
+ bufPtrs[i][outX] = mPlane.data[idx];
+ outX++;
+ }
+
+ // Fill the remaining right-edge of the buffer by extending the last
+ // value.
+ unsigned char right_padding_value = bufPtrs[i][outX - 1];
+ for (; outX < mPaddedRowLength; outX++) {
+ bufPtrs[i][outX] = right_padding_value;
+ }
+ }
+
+ return bufPtrs;
+}
+
+template <typename T>
+void safeDelete(T& t) {
+ delete t;
+ t = nullptr;
+}
+
+template <typename T>
+void safeDeleteArray(T& t) {
+ delete[] t;
+ t = nullptr;
+}
+
+Transform::Transform(int origX, int origY, int oneX, int oneY)
+ : mOrigX(origX), mOrigY(origY), mOneX(oneX), mOneY(oneY) {
+ if (origX == oneX || origY == oneY) {
+ // Handle the degenerate case of cropping to a 0x0 rectangle.
+ mMat00 = 0;
+ mMat01 = 0;
+ mMat10 = 0;
+ mMat11 = 0;
+ return;
+ }
+
+ if (oneX > origX && oneY > origY) {
+ // 0-degree rotation
+ mMat00 = 1;
+ mMat01 = 0;
+ mMat10 = 0;
+ mMat11 = 1;
+ mOutputWidth = abs(oneX - origX);
+ mOutputHeight = abs(oneY - origY);
+ } else if (oneX < origX && oneY > origY) {
+ // 90-degree CCW rotation
+ mMat00 = 0;
+ mMat01 = -1;
+ mMat10 = 1;
+ mMat11 = 0;
+ mOutputWidth = abs(oneY - origY);
+ mOutputHeight = abs(oneX - origX);
+ } else if (oneX > origX && oneY < origY) {
+ // 270-degree CCW rotation
+ mMat00 = 0;
+ mMat01 = 1;
+ mMat10 = -1;
+ mMat11 = 0;
+ mOutputWidth = abs(oneY - origY);
+ mOutputHeight = abs(oneX - origX);;
+ } else if (oneX < origX && oneY < origY) {
+ // 180-degree CCW rotation
+ mMat00 = -1;
+ mMat01 = 0;
+ mMat10 = 0;
+ mMat11 = -1;
+ mOutputWidth = abs(oneX - origX);
+ mOutputHeight = abs(oneY - origY);
+ }
+}
+
+Transform Transform::forCropFollowedByRotation(int cropLeft, int cropTop, int cropRight,
+ int cropBottom, int rot90) {
+ // The input crop-region excludes cropRight and cropBottom, so transform the
+ // crop rect such that it defines the entire valid region of pixels
+ // inclusively.
+ cropRight -= 1;
+ cropBottom -= 1;
+
+ int cropXLow = min(cropLeft, cropRight);
+ int cropYLow = min(cropTop, cropBottom);
+ int cropXHigh = max(cropLeft, cropRight);
+ int cropYHigh = max(cropTop, cropBottom);
+ rot90 %= 4;
+ if (rot90 == 0) {
+ return Transform(cropXLow, cropYLow, cropXHigh + 1, cropYHigh + 1);
+ } else if (rot90 == 1) {
+ return Transform(cropXHigh, cropYLow, cropXLow - 1, cropYHigh + 1);
+ } else if (rot90 == 2) {
+ return Transform(cropXHigh, cropYHigh, cropXLow - 1, cropYLow - 1);
+ } else if (rot90 == 3) {
+ return Transform(cropXLow, cropYHigh, cropXHigh + 1, cropYLow - 1);
+ }
+ // Impossible case.
+ return Transform(cropXLow, cropYLow, cropXHigh + 1, cropYHigh + 1);
+}
+
+bool Transform::operator==(const Transform& other) const {
+ return other.mOrigX == mOrigX && //
+ other.mOrigY == mOrigY && //
+ other.mOneX == mOneX && //
+ other.mOneY == mOneY;
+}
+
+/**
+ * Transforms the input coordinates. Coordinates outside the cropped region
+ * are clamped to valid values.
+ */
+void Transform::map(int x, int y, int* outX, int* outY) const {
+ x = max(x, 0);
+ y = max(y, 0);
+ x = min(x, getOutputWidth() - 1);
+ y = min(y, getOutputHeight() - 1);
+ *outX = x * mMat00 + y * mMat01 + mOrigX;
+ *outY = x * mMat10 + y * mMat11 + mOrigY;
+}
+
+int compress(int img_width, int img_height, RowIterator<16>& y_row_generator,
+ RowIterator<8>& cb_row_generator, RowIterator<8>& cr_row_generator,
+ unsigned char* out_buf, size_t out_buf_capacity, std::function<void(size_t)> flush,
+ int quality) {
+ // libjpeg requires the use of setjmp/longjmp to recover from errors. Since
+ // this doesn't play well with RAII, we must use pointers and manually call
+ // delete. See POSIX documentation for longjmp() for details on why the
+ // volatile keyword is necessary.
+ volatile jpeg_compress_struct cinfov;
+
+ jpeg_compress_struct& cinfo =
+ *const_cast<struct jpeg_compress_struct*>(&cinfov);
+
+ JSAMPROW* volatile yArr = nullptr;
+ JSAMPROW* volatile cbArr = nullptr;
+ JSAMPROW* volatile crArr = nullptr;
+
+ JSAMPARRAY imgArr[3];
+
+ // Error handling
+
+ struct my_error_mgr {
+ struct jpeg_error_mgr pub;
+ jmp_buf setjmp_buffer;
+ } err;
+
+ cinfo.err = jpeg_std_error(&err.pub);
+
+ // Default error_exit will call exit(), so override
+ // to return control via setjmp/longjmp.
+ err.pub.error_exit = [](j_common_ptr cinfo) {
+ my_error_mgr* myerr = reinterpret_cast<my_error_mgr*>(cinfo->err);
+
+ (*cinfo->err->output_message)(cinfo);
+
+ // Return control to the setjmp point (see call to setjmp()).
+ longjmp(myerr->setjmp_buffer, 1);
+ };
+
+ cinfo.err = (struct jpeg_error_mgr*)&err;
+
+ // Set the setjmp point to return to in case of error.
+ if (setjmp(err.setjmp_buffer)) {
+ // If libjpeg hits an error, control will jump to this point (see call to
+ // longjmp()).
+ jpeg_destroy_compress(&cinfo);
+
+ safeDeleteArray(yArr);
+ safeDeleteArray(cbArr);
+ safeDeleteArray(crArr);
+
+ return -1;
+ }
+
+ // Create jpeg compression context
+ jpeg_create_compress(&cinfo);
+
+ // Stores data needed by our c-style callbacks into libjpeg
+ struct ClientData {
+ unsigned char* out_buf;
+ size_t out_buf_capacity;
+ std::function<void(size_t)> flush;
+ int totalOutputBytes;
+ } clientData{out_buf, out_buf_capacity, flush, 0};
+
+ cinfo.client_data = &clientData;
+
+ // Initialize destination manager
+ jpeg_destination_mgr dest;
+
+ dest.init_destination = [](j_compress_ptr cinfo) {
+ ClientData& cdata = *reinterpret_cast<ClientData*>(cinfo->client_data);
+
+ cinfo->dest->next_output_byte = cdata.out_buf;
+ cinfo->dest->free_in_buffer = cdata.out_buf_capacity;
+ };
+
+ dest.empty_output_buffer = [](j_compress_ptr cinfo) -> boolean {
+ ClientData& cdata = *reinterpret_cast<ClientData*>(cinfo->client_data);
+
+ size_t numBytesInBuffer = cdata.out_buf_capacity;
+ cdata.flush(numBytesInBuffer);
+ cdata.totalOutputBytes += numBytesInBuffer;
+
+ // Reset the buffer
+ cinfo->dest->next_output_byte = cdata.out_buf;
+ cinfo->dest->free_in_buffer = cdata.out_buf_capacity;
+
+ return true;
+ };
+
+ dest.term_destination = [](j_compress_ptr cinfo __unused) {
+ // do nothing to terminate the output buffer
+ };
+
+ cinfo.dest = &dest;
+
+ // Set jpeg parameters
+ cinfo.image_width = img_width;
+ cinfo.image_height = img_height;
+ cinfo.input_components = 3;
+
+ // Set defaults based on the above values
+ jpeg_set_defaults(&cinfo);
+
+ jpeg_set_quality(&cinfo, quality, true);
+
+ cinfo.dct_method = JDCT_IFAST;
+
+ cinfo.raw_data_in = true;
+
+ jpeg_set_colorspace(&cinfo, JCS_YCbCr);
+
+ cinfo.comp_info[0].h_samp_factor = 2;
+ cinfo.comp_info[0].v_samp_factor = 2;
+ cinfo.comp_info[1].h_samp_factor = 1;
+ cinfo.comp_info[1].v_samp_factor = 1;
+ cinfo.comp_info[2].h_samp_factor = 1;
+ cinfo.comp_info[2].v_samp_factor = 1;
+
+ jpeg_start_compress(&cinfo, true);
+
+ yArr = new JSAMPROW[cinfo.comp_info[0].v_samp_factor * DCTSIZE];
+ cbArr = new JSAMPROW[cinfo.comp_info[1].v_samp_factor * DCTSIZE];
+ crArr = new JSAMPROW[cinfo.comp_info[2].v_samp_factor * DCTSIZE];
+
+ imgArr[0] = const_cast<JSAMPARRAY>(yArr);
+ imgArr[1] = const_cast<JSAMPARRAY>(cbArr);
+ imgArr[2] = const_cast<JSAMPARRAY>(crArr);
+
+ for (int y = 0; y < img_height; y += DCTSIZE * 2) {
+ std::array<unsigned char*, 16> yData = y_row_generator.loadAt(y);
+ std::array<unsigned char*, 8> cbData = cb_row_generator.loadAt(y / 2);
+ std::array<unsigned char*, 8> crData = cr_row_generator.loadAt(y / 2);
+
+ for (int row = 0; row < DCTSIZE * 2; row++) {
+ yArr[row] = yData[row];
+ }
+ for (int row = 0; row < DCTSIZE; row++) {
+ cbArr[row] = cbData[row];
+ crArr[row] = crData[row];
+ }
+
+ jpeg_write_raw_data(&cinfo, imgArr, DCTSIZE * 2);
+ }
+
+ jpeg_finish_compress(&cinfo);
+
+ int numBytesInBuffer = cinfo.dest->next_output_byte - out_buf;
+
+ flush(numBytesInBuffer);
+
+ clientData.totalOutputBytes += numBytesInBuffer;
+
+ safeDeleteArray(yArr);
+ safeDeleteArray(cbArr);
+ safeDeleteArray(crArr);
+
+ jpeg_destroy_compress(&cinfo);
+
+ return clientData.totalOutputBytes;
+}
+
+int compress(
+ /** Input image dimensions */
+ int width, int height,
+ /** Y Plane */
+ unsigned char* yBuf, int yPStride, int yRStride,
+ /** Cb Plane */
+ unsigned char* cbBuf, int cbPStride, int cbRStride,
+ /** Cr Plane */
+ unsigned char* crBuf, int crPStride, int crRStride,
+ /** Output */
+ unsigned char* outBuf, size_t outBufCapacity,
+ /** Jpeg compression parameters */
+ int quality,
+ /** Crop */
+ int cropLeft, int cropTop, int cropRight, int cropBottom,
+ /** Rotation (multiple of 90). For example, rot90 = 1 implies a 90 degree
+ * rotation. */
+ int rot90) {
+ int finalWidth;
+ int finalHeight;
+ finalWidth = cropRight - cropLeft;
+ finalHeight = cropBottom - cropTop;
+
+ rot90 %= 4;
+ // for 90 and 270-degree rotations, flip the final width and height
+ if (rot90 == 1) {
+ finalWidth = cropBottom - cropTop;
+ finalHeight = cropRight - cropLeft;
+ } else if (rot90 == 3) {
+ finalWidth = cropBottom - cropTop;
+ finalHeight = cropRight - cropLeft;
+ }
+
+ const Plane yP = {width, height, yBuf, yPStride, yRStride};
+ const Plane cbP = {width / 2, height / 2, cbBuf, cbPStride, cbRStride};
+ const Plane crP = {width / 2, height / 2, crBuf, crPStride, crRStride};
+
+ auto flush = [](size_t numBytes __unused) {
+ // do nothing
+ };
+
+ // Round up to the nearest multiple of 64.
+ int y_row_length = (finalWidth + 16 + 63) & ~63;
+ int cb_row_length = (finalWidth / 2 + 16 + 63) & ~63;
+ int cr_row_length = (finalWidth / 2 + 16 + 63) & ~63;
+
+ Transform yTrans = Transform::forCropFollowedByRotation(
+ cropLeft, cropTop, cropRight, cropBottom, rot90);
+
+ Transform chromaTrans = Transform::forCropFollowedByRotation(
+ cropLeft / 2, cropTop / 2, cropRight / 2, cropBottom / 2, rot90);
+
+ RowIterator<16> yIter(yP, yTrans, y_row_length);
+ RowIterator<8> cbIter(cbP, chromaTrans, cb_row_length);
+ RowIterator<8> crIter(crP, chromaTrans, cr_row_length);
+
+ return compress(finalWidth, finalHeight, yIter, cbIter, crIter, outBuf, outBufCapacity, flush,
+ quality);
+}
+
+extern "C" {
+
+static jint CameraExtensionJpegProcessor_compressJpegFromYUV420p(
+ JNIEnv* env, jclass clazz __unused,
+ /** Input image dimensions */
+ jint width, jint height,
+ /** Y Plane */
+ jobject yBuf, jint yPStride, jint yRStride,
+ /** Cb Plane */
+ jobject cbBuf, jint cbPStride, jint cbRStride,
+ /** Cr Plane */
+ jobject crBuf, jint crPStride, jint crRStride,
+ /** Output */
+ jobject outBuf, jint outBufCapacity,
+ /** Jpeg compression parameters */
+ jint quality,
+ /** Crop */
+ jint cropLeft, jint cropTop, jint cropRight, jint cropBottom,
+ /** Rotation (multiple of 90). For example, rot90 = 1 implies a 90 degree
+ * rotation. */
+ jint rot90) {
+ jbyte* y = (jbyte*)env->GetDirectBufferAddress(yBuf);
+ jbyte* cb = (jbyte*)env->GetDirectBufferAddress(cbBuf);
+ jbyte* cr = (jbyte*)env->GetDirectBufferAddress(crBuf);
+ jbyte* out = (jbyte*)env->GetDirectBufferAddress(outBuf);
+
+ size_t actualJpegSize = compress(width, height,
+ (unsigned char*)y, yPStride, yRStride,
+ (unsigned char*)cb, cbPStride, cbRStride,
+ (unsigned char*)cr, crPStride, crRStride,
+ (unsigned char*)out, (size_t)outBufCapacity,
+ quality, cropLeft, cropTop, cropRight, cropBottom, rot90);
+
+ size_t finalJpegSize = actualJpegSize + sizeof(CameraBlob);
+ if (finalJpegSize > outBufCapacity) {
+ ALOGE("%s: Final jpeg buffer %zu not large enough for the jpeg blob header with "\
+ "capacity %d", __FUNCTION__, finalJpegSize, outBufCapacity);
+ return actualJpegSize;
+ }
+
+ int8_t* header = static_cast<int8_t *> (out) +
+ (outBufCapacity - sizeof(CameraBlob));
+ CameraBlob *blob = reinterpret_cast<CameraBlob *> (header);
+ blob->blobId = CameraBlobId::JPEG;
+ blob->blobSize = actualJpegSize;
+
+ return actualJpegSize;
+}
+
+} // extern "C"
+
+static const JNINativeMethod gCameraExtensionJpegProcessorMethods[] = {
+ {"compressJpegFromYUV420pNative",
+ "(IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IIIIIII)I",
+ (void*)CameraExtensionJpegProcessor_compressJpegFromYUV420p}};
+
+// Get all the required offsets in java class and register native functions
+int register_android_hardware_camera2_impl_CameraExtensionJpegProcessor(JNIEnv* env) {
+ // Register native functions
+ return RegisterMethodsOrDie(env, CAMERA_PROCESSOR_CLASS_NAME,
+ gCameraExtensionJpegProcessorMethods, NELEM(gCameraExtensionJpegProcessorMethods));
+}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index d11ee3a875aa..451ea93349f7 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -27,7 +27,6 @@
#include <android-base/chrono_utils.h>
#include <android/graphics/region.h>
#include <android/gui/BnScreenCaptureListener.h>
-#include <android/hardware/display/IDeviceProductInfoConstants.h>
#include <android/os/IInputConstants.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_hardware_HardwareBuffer.h>
@@ -98,6 +97,8 @@ static struct {
jfieldID supportedColorModes;
jfieldID activeColorMode;
jfieldID hdrCapabilities;
+ jfieldID autoLowLatencyModeSupported;
+ jfieldID gameContentTypeSupported;
} gDynamicDisplayInfoClassInfo;
static struct {
@@ -1021,24 +1022,16 @@ static jobject convertDeviceProductInfoToJavaObject(
} else {
LOG_FATAL("Unknown alternative for variant DeviceProductInfo::ManufactureOrModelDate");
}
- jint connectionToSinkType;
- // Relative address maps to HDMI physical address. All addresses are 4 digits long allowing
- // for a 5–device-deep hierarchy. For more information, refer:
- // Section 8.7 - Physical Address of HDMI Specification Version 1.3a
- using android::hardware::display::IDeviceProductInfoConstants;
- if (info->relativeAddress.size() != 4) {
- connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_UNKNOWN;
- } else if (info->relativeAddress[0] == 0) {
- connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_BUILT_IN;
- } else if (info->relativeAddress[1] == 0) {
- connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_DIRECT;
- } else {
- connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_TRANSITIVE;
+ auto relativeAddress = env->NewIntArray(info->relativeAddress.size());
+ auto relativeAddressData = env->GetIntArrayElements(relativeAddress, nullptr);
+ for (int i = 0; i < info->relativeAddress.size(); i++) {
+ relativeAddressData[i] = info->relativeAddress[i];
}
+ env->ReleaseIntArrayElements(relativeAddress, relativeAddressData, 0);
return env->NewObject(gDeviceProductInfoClassInfo.clazz, gDeviceProductInfoClassInfo.ctor, name,
manufacturerPnpId, productId, modelYear, manufactureDate,
- connectionToSinkType);
+ relativeAddress);
}
static jobject nativeGetStaticDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) {
@@ -1134,6 +1127,11 @@ static jobject nativeGetDynamicDisplayInfo(JNIEnv* env, jclass clazz, jobject to
env->SetObjectField(object, gDynamicDisplayInfoClassInfo.hdrCapabilities,
convertDeviceProductInfoToJavaObject(env, info.hdrCapabilities));
+ env->SetBooleanField(object, gDynamicDisplayInfoClassInfo.autoLowLatencyModeSupported,
+ info.autoLowLatencyModeSupported);
+
+ env->SetBooleanField(object, gDynamicDisplayInfoClassInfo.gameContentTypeSupported,
+ info.gameContentTypeSupported);
return object;
}
@@ -1458,20 +1456,6 @@ static void nativeReparent(JNIEnv* env, jclass clazz, jlong transactionObj,
transaction->reparent(ctrl, newParent);
}
-static jboolean nativeGetAutoLowLatencyModeSupport(JNIEnv* env, jclass clazz, jobject tokenObject) {
- sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
- if (token == NULL) return NULL;
-
- return SurfaceComposerClient::getAutoLowLatencyModeSupport(token);
-}
-
-static jboolean nativeGetGameContentTypeSupport(JNIEnv* env, jclass clazz, jobject tokenObject) {
- sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
- if (token == NULL) return NULL;
-
- return SurfaceComposerClient::getGameContentTypeSupport(token);
-}
-
static void nativeSetAutoLowLatencyMode(JNIEnv* env, jclass clazz, jobject tokenObject, jboolean on) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
if (token == NULL) return;
@@ -1821,12 +1805,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeGetDisplayNativePrimaries },
{"nativeSetActiveColorMode", "(Landroid/os/IBinder;I)Z",
(void*)nativeSetActiveColorMode},
- {"nativeGetAutoLowLatencyModeSupport", "(Landroid/os/IBinder;)Z",
- (void*)nativeGetAutoLowLatencyModeSupport },
{"nativeSetAutoLowLatencyMode", "(Landroid/os/IBinder;Z)V",
(void*)nativeSetAutoLowLatencyMode },
- {"nativeGetGameContentTypeSupport", "(Landroid/os/IBinder;)Z",
- (void*)nativeGetGameContentTypeSupport },
{"nativeSetGameContentType", "(Landroid/os/IBinder;Z)V",
(void*)nativeSetGameContentType },
{"nativeGetCompositionDataspaces", "()[I",
@@ -1934,6 +1914,10 @@ int register_android_view_SurfaceControl(JNIEnv* env)
gDynamicDisplayInfoClassInfo.hdrCapabilities =
GetFieldIDOrDie(env, dynamicInfoClazz, "hdrCapabilities",
"Landroid/view/Display$HdrCapabilities;");
+ gDynamicDisplayInfoClassInfo.autoLowLatencyModeSupported =
+ GetFieldIDOrDie(env, dynamicInfoClazz, "autoLowLatencyModeSupported", "Z");
+ gDynamicDisplayInfoClassInfo.gameContentTypeSupported =
+ GetFieldIDOrDie(env, dynamicInfoClazz, "gameContentTypeSupported", "Z");
jclass modeClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayMode");
gDisplayModeClassInfo.clazz = MakeGlobalRefOrDie(env, modeClazz);
@@ -1986,7 +1970,7 @@ int register_android_view_SurfaceControl(JNIEnv* env)
"Ljava/lang/String;"
"Ljava/lang/Integer;"
"Landroid/hardware/display/DeviceProductInfo$ManufactureDate;"
- "I)V");
+ "[I)V");
jclass deviceProductInfoManufactureDateClazz =
FindClassOrDie(env, "android/hardware/display/DeviceProductInfo$ManufactureDate");
diff --git a/core/jni/android_view_SurfaceControlFpsListener.cpp b/core/jni/android_view_SurfaceControlFpsListener.cpp
new file mode 100644
index 000000000000..6fa12e510459
--- /dev/null
+++ b/core/jni/android_view_SurfaceControlFpsListener.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceControlFpsListener"
+
+#include <android/gui/BnFpsListener.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <nativehelper/JNIHelp.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+
+#include "android_util_Binder.h"
+#include "core_jni_helpers.h"
+
+namespace android {
+
+namespace {
+
+struct {
+ jclass mClass;
+ jmethodID mDispatchOnFpsReported;
+} gListenerClassInfo;
+
+struct SurfaceControlFpsListener : public gui::BnFpsListener {
+ SurfaceControlFpsListener(JNIEnv* env, jobject listener)
+ : mListener(env->NewWeakGlobalRef(listener)) {}
+
+ binder::Status onFpsReported(float fps) override {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onFpsReported.");
+
+ jobject listener = env->NewGlobalRef(mListener);
+ if (listener == NULL) {
+ // Weak reference went out of scope
+ return binder::Status::ok();
+ }
+ env->CallStaticVoidMethod(gListenerClassInfo.mClass,
+ gListenerClassInfo.mDispatchOnFpsReported, listener,
+ static_cast<jfloat>(fps));
+ env->DeleteGlobalRef(listener);
+
+ if (env->ExceptionCheck()) {
+ ALOGE("SurfaceControlFpsListener.onFpsReported() failed.");
+ LOGE_EX(env);
+ env->ExceptionClear();
+ }
+ return binder::Status::ok();
+ }
+
+protected:
+ virtual ~SurfaceControlFpsListener() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->DeleteWeakGlobalRef(mListener);
+ }
+
+private:
+ jweak mListener;
+};
+
+jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) {
+ SurfaceControlFpsListener* listener = new SurfaceControlFpsListener(env, obj);
+ listener->incStrong((void*)nativeCreate);
+ return reinterpret_cast<jlong>(listener);
+}
+
+void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
+ SurfaceControlFpsListener* listener = reinterpret_cast<SurfaceControlFpsListener*>(ptr);
+ listener->decStrong((void*)nativeCreate);
+}
+
+void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr, jlong layerObj) {
+ sp<SurfaceControlFpsListener> listener = reinterpret_cast<SurfaceControlFpsListener*>(ptr);
+ auto layer = reinterpret_cast<SurfaceControl*>(layerObj);
+ sp<IBinder> layerHandle = layer != nullptr ? layer->getHandle() : nullptr;
+ if (SurfaceComposerClient::addFpsListener(layerHandle, listener) != OK) {
+ constexpr auto error_msg = "Couldn't addFpsListener";
+ ALOGE(error_msg);
+ jniThrowRuntimeException(env, error_msg);
+ }
+}
+
+void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
+ sp<SurfaceControlFpsListener> listener = reinterpret_cast<SurfaceControlFpsListener*>(ptr);
+
+ if (SurfaceComposerClient::removeFpsListener(listener) != OK) {
+ constexpr auto error_msg = "Couldn't removeFpsListener";
+ ALOGE(error_msg);
+ jniThrowRuntimeException(env, error_msg);
+ }
+}
+
+const JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ {"nativeCreate", "(Landroid/view/SurfaceControlFpsListener;)J", (void*)nativeCreate},
+ {"nativeDestroy", "(J)V", (void*)nativeDestroy},
+ {"nativeRegister", "(JJ)V", (void*)nativeRegister},
+ {"nativeUnregister", "(J)V", (void*)nativeUnregister}};
+
+} // namespace
+
+int register_android_view_SurfaceControlFpsListener(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "android/view/SurfaceControlFpsListener", gMethods,
+ NELEM(gMethods));
+ LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ jclass clazz = env->FindClass("android/view/SurfaceControlFpsListener");
+ gListenerClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
+ gListenerClassInfo.mDispatchOnFpsReported =
+ env->GetStaticMethodID(clazz, "dispatchOnFpsReported",
+ "(Landroid/view/SurfaceControlFpsListener;F)V");
+ return 0;
+}
+
+} // namespace android
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index c882431c9366..ec502c3c272f 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -174,10 +174,10 @@ message DisplayContentProto {
// Use root_display_area instead
optional WindowContainerProto window_container = 1 [deprecated=true];
optional int32 id = 2;
- reserved 3; // stacks
- optional DockedStackDividerControllerProto docked_stack_divider_controller = 4 [deprecated=true];
+ reserved 3; // RootTasks
+ optional DockedTaskDividerControllerProto docked_task_divider_controller = 4 [deprecated=true];
// Will be removed soon.
- optional PinnedStackControllerProto pinned_stack_controller = 5 [deprecated=true];
+ optional PinnedTaskControllerProto pinned_task_controller = 5 [deprecated=true];
/* non app windows */
repeated WindowTokenProto above_app_windows = 6 [deprecated=true];
repeated WindowTokenProto below_app_windows = 7 [deprecated=true];
@@ -256,15 +256,15 @@ message DisplayRotationProto {
optional int32 last_orientation = 5 [(.android.typedef) = "android.content.pm.ActivityInfo.ScreenOrientation"];
}
-/* represents DockedStackDividerController */
-message DockedStackDividerControllerProto {
+/* represents DockedTaskDividerController */
+message DockedTaskDividerControllerProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional bool minimized_dock = 1 [deprecated=true];
}
-/* represents PinnedStackController */
-message PinnedStackControllerProto {
+/* represents PinnedTaskController */
+message PinnedTaskControllerProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional .android.graphics.RectProto default_bounds = 1 [deprecated=true];
@@ -406,6 +406,8 @@ message WindowStateProto {
optional int64 finished_seamless_rotation_frame = 40;
optional WindowFramesProto window_frames = 41;
optional bool force_seamless_rotation = 42;
+ optional bool in_size_compat_mode = 43;
+ optional float global_scale = 44;
}
message IdentifierProto {
@@ -516,6 +518,7 @@ message WindowFramesProto {
optional .android.graphics.RectProto visible_insets = 13 [deprecated=true];
optional .android.graphics.RectProto stable_insets = 14 [deprecated=true];
optional .android.graphics.RectProto outsets = 15;
+ optional .android.graphics.RectProto compat_frame = 16;
}
message InsetsSourceProviderProto {
diff --git a/core/res/Android.bp b/core/res/Android.bp
index 4cf9cfb7120a..b988b5a92af7 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -44,11 +44,73 @@ license {
],
}
+genrule {
+ name: "remote-color-resources-compile-public",
+ tools: ["aapt2"],
+ srcs: [
+ "remote_color_resources_res/values/public.xml",
+ ],
+ out: ["values_public.arsc.flat"],
+ cmd: "$(location aapt2) compile $(in) -o $(genDir)",
+}
+
+genrule {
+ name: "remote-color-resources-compile-colors",
+ tools: ["aapt2"],
+ srcs: [
+ "remote_color_resources_res/values/colors.xml",
+ ],
+ out: ["values_colors.arsc.flat"],
+ cmd: "$(location aapt2) compile $(in) -o $(genDir)",
+}
+
+genrule {
+ name: "remote-color-resources-apk",
+ tools: ["aapt2"],
+ // The first input file in the list must be the manifest
+ srcs: [
+ "RemoteThemeColorsAndroidManifest.xml",
+ ":remote-color-resources-compile-public",
+ ":remote-color-resources-compile-colors",
+ ],
+ out: ["remote-color-resources.apk"],
+ cmd: "$(location aapt2) link -o $(out) --manifest $(in)"
+}
+
+genrule {
+ name: "remote-color-resources-arsc",
+ srcs: [":remote-color-resources-apk"],
+ out: ["res/raw/remote_views_color_resources.arsc"],
+ cmd: "mkdir -p $(genDir)/remote-color-resources-arsc && "
+ + "unzip -x $(in) resources.arsc -d $(genDir)/remote-color-resources-arsc && "
+ + "mkdir -p $$(dirname $(out)) && "
+ + "mv $(genDir)/remote-color-resources-arsc/resources.arsc $(out) && "
+ + "echo 'Created $(out)'"
+}
+
+genrule {
+ name: "remote-color-resources-arsc-zip",
+ tools: ["soong_zip"],
+ srcs: [
+ ":remote-color-resources-arsc",
+ "remote_color_resources_res/symbols.xml",
+ ],
+ out: ["remote_views_color_resources.zip"],
+ cmd: "INPUTS=($(in)) && "
+ + "RES_DIR=$$(dirname $$(dirname $${INPUTS[0]})) && "
+ + "mkdir -p $$RES_DIR/values && "
+ + "cp $${INPUTS[1]} $$RES_DIR/values && "
+ + "$(location soong_zip) -o $(out) -C $$RES_DIR -D $$RES_DIR && "
+ + "cp $(out) ."
+}
+
android_app {
name: "framework-res",
sdk_version: "core_platform",
certificate: "platform",
+ srcs: [":remote-color-resources-arsc"],
+
// Disable dexpreopt and verify_uses_libraries check as the app
// contains no Java code to be dexpreopted.
enforce_uses_libs: false,
@@ -72,6 +134,10 @@ android_app {
"--auto-add-overlay",
],
+ resource_zips: [
+ ":remote-color-resources-arsc-zip",
+ ],
+
// Create package-export.apk, which other packages can use to get
// PRODUCT-agnostic resource data like IDs and type definitions.
export_package_resources: true,
@@ -96,6 +162,7 @@ filegroup {
srcs: [
"assets/**/*",
"res/**/*",
+ ":remote-color-resources-arsc",
],
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5dd85805cfc1..7ad016c8ce47 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2641,6 +2641,16 @@
android:label="@string/permlab_manageProfileAndDeviceOwners"
android:description="@string/permdesc_manageProfileAndDeviceOwners" />
+ <!-- @TestApi @hide Allows an application to reset the record of previous system update freeze
+ periods. -->
+ <permission android:name="android.permission.CLEAR_FREEZE_PERIOD"
+ android:protectionLevel="signature" />
+
+ <!-- @TestApi @hide Allows an application to force available DevicePolicyManager logs to
+ DPC. -->
+ <permission android:name="android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to get full detailed information about
recently running tasks, with full fidelity to the real state.
@hide -->
diff --git a/core/res/RemoteThemeColorsAndroidManifest.xml b/core/res/RemoteThemeColorsAndroidManifest.xml
new file mode 100644
index 000000000000..11970fd18979
--- /dev/null
+++ b/core/res/RemoteThemeColorsAndroidManifest.xml
@@ -0,0 +1,5 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+<application/>
+</manifest>
+
diff --git a/core/res/remote_color_resources_res/symbols.xml b/core/res/remote_color_resources_res/symbols.xml
new file mode 100644
index 000000000000..82d5e3e2da6d
--- /dev/null
+++ b/core/res/remote_color_resources_res/symbols.xml
@@ -0,0 +1,4 @@
+<resources>
+ <!-- ARSC file used to overlay local colors when rendering a RemoteViews -->
+ <java-symbol type="raw" name="remote_views_color_resources" />
+</resources>
diff --git a/core/res/remote_color_resources_res/values/colors.xml b/core/res/remote_color_resources_res/values/colors.xml
new file mode 100644
index 000000000000..295f16e959e6
--- /dev/null
+++ b/core/res/remote_color_resources_res/values/colors.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- Note: the values of the colors doesn't really matter (they will always be overwritten before used), but they help a lot debugging, to find out which color is where in the ARSC file. -->
+ <color name="system_primary_0">#01010101</color>
+ <color name="system_primary_50">#02020202</color>
+ <color name="system_primary_100">#03030303</color>
+ <color name="system_primary_200">#04040404</color>
+ <color name="system_primary_300">#05050505</color>
+ <color name="system_primary_400">#06060606</color>
+ <color name="system_primary_500">#07070707</color>
+ <color name="system_primary_600">#08080808</color>
+ <color name="system_primary_700">#09090909</color>
+ <color name="system_primary_800">#0a0a0a0a</color>
+ <color name="system_primary_900">#0b0b0b0b</color>
+ <color name="system_primary_1000">#0c0c0c0c</color>
+ <color name="system_secondary_0">#10101010</color>
+ <color name="system_secondary_50">#20202020</color>
+ <color name="system_secondary_100">#30303030</color>
+ <color name="system_secondary_200">#40404040</color>
+ <color name="system_secondary_300">#50505050</color>
+ <color name="system_secondary_400">#60606060</color>
+ <color name="system_secondary_500">#70707070</color>
+ <color name="system_secondary_600">#80808080</color>
+ <color name="system_secondary_700">#90909090</color>
+ <color name="system_secondary_800">#a0a0a0a0</color>
+ <color name="system_secondary_900">#b0b0b0b0</color>
+ <color name="system_secondary_1000">#c0c0c0c0</color>
+ <color name="system_neutral_0">#1f1f1f1f</color>
+ <color name="system_neutral_50">#2f2f2f2f</color>
+ <color name="system_neutral_100">#3f3f3f3f</color>
+ <color name="system_neutral_200">#4f4f4f4f</color>
+ <color name="system_neutral_300">#5f5f5f5f</color>
+ <color name="system_neutral_400">#6f6f6f6f</color>
+ <color name="system_neutral_500">#7f7f7f7f</color>
+ <color name="system_neutral_600">#8f8f8f8f</color>
+ <color name="system_neutral_700">#9f9f9f9f</color>
+ <color name="system_neutral_800">#afafafaf</color>
+ <color name="system_neutral_900">#bfbfbfbf</color>
+ <color name="system_neutral_1000">#cfcfcfcf</color>
+</resources>
diff --git a/core/res/remote_color_resources_res/values/public.xml b/core/res/remote_color_resources_res/values/public.xml
new file mode 100644
index 000000000000..e628f09b8327
--- /dev/null
+++ b/core/res/remote_color_resources_res/values/public.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <public-group type="color" first-id="0x0106001d">
+ <public name="system_primary_0" />
+ <public name="system_primary_50" />
+ <public name="system_primary_100" />
+ <public name="system_primary_200" />
+ <public name="system_primary_300" />
+ <public name="system_primary_400" />
+ <public name="system_primary_500" />
+ <public name="system_primary_600" />
+ <public name="system_primary_700" />
+ <public name="system_primary_800" />
+ <public name="system_primary_900" />
+ <public name="system_primary_1000" />
+ <public name="system_secondary_0" />
+ <public name="system_secondary_50" />
+ <public name="system_secondary_100" />
+ <public name="system_secondary_200" />
+ <public name="system_secondary_300" />
+ <public name="system_secondary_400" />
+ <public name="system_secondary_500" />
+ <public name="system_secondary_600" />
+ <public name="system_secondary_700" />
+ <public name="system_secondary_800" />
+ <public name="system_secondary_900" />
+ <public name="system_secondary_1000" />
+ <public name="system_neutral_0" />
+ <public name="system_neutral_50" />
+ <public name="system_neutral_100" />
+ <public name="system_neutral_200" />
+ <public name="system_neutral_300" />
+ <public name="system_neutral_400" />
+ <public name="system_neutral_500" />
+ <public name="system_neutral_600" />
+ <public name="system_neutral_700" />
+ <public name="system_neutral_800" />
+ <public name="system_neutral_900" />
+ <public name="system_neutral_1000" />
+ </public-group>
+</resources>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 62114630a328..1de1d049197c 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -17,8 +17,8 @@
<NotificationHeaderView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/notification_header"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/notification_header_solo_height"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_header_height"
android:layout_marginBottom="@dimen/notification_header_margin_bottom"
android:clipChildren="false"
android:gravity="center_vertical"
diff --git a/core/res/res/layout/notification_template_material_big_base.xml b/core/res/res/layout/notification_template_material_big_base.xml
index de537b205866..2d1c3422ca36 100644
--- a/core/res/res/layout/notification_template_material_big_base.xml
+++ b/core/res/res/layout/notification_template_material_big_base.xml
@@ -38,11 +38,7 @@
android:layout_gravity="top"
>
- <include
- layout="@layout/notification_template_header"
- android:layout_width="match_parent"
- android:layout_height="@dimen/notification_header_big_height"
- />
+ <include layout="@layout/notification_template_header" />
<LinearLayout
android:id="@+id/notification_main_column"
diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
index 696cb6572e29..bdd4430a7985 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -36,7 +36,6 @@
layout="@layout/notification_template_header"
android:layout_width="match_parent"
android:layout_height="@dimen/media_notification_header_height"
- android:layout_gravity="start"
/>
<LinearLayout
diff --git a/core/res/res/layout/notification_template_material_big_picture.xml b/core/res/res/layout/notification_template_material_big_picture.xml
index e1b7bc4d7bca..6f3c77ff72a4 100644
--- a/core/res/res/layout/notification_template_material_big_picture.xml
+++ b/core/res/res/layout/notification_template_material_big_picture.xml
@@ -23,11 +23,7 @@
android:clipChildren="false"
>
- <include
- layout="@layout/notification_template_header"
- android:layout_width="match_parent"
- android:layout_height="@dimen/notification_header_big_height"
- />
+ <include layout="@layout/notification_template_header" />
<include layout="@layout/notification_template_right_icon" />
diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
index 2452a32b21eb..2954ba2a0903 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -23,11 +23,7 @@
android:tag="bigText"
>
- <include
- layout="@layout/notification_template_header"
- android:layout_width="match_parent"
- android:layout_height="@dimen/notification_header_big_height"
- />
+ <include layout="@layout/notification_template_header" />
<com.android.internal.widget.RemeasuringLinearLayout
android:id="@+id/notification_action_list_margin_target"
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 7daccd2b8544..baffdd5ac0f1 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -32,7 +32,8 @@
/>
<include layout="@layout/notification_template_header"
android:layout_width="match_parent"
- android:layout_height="@dimen/media_notification_header_height" />
+ android:layout_height="@dimen/media_notification_header_height"
+ />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/core/res/res/values-night/values.xml b/core/res/res/values-night/values.xml
index 952cdd08451c..b1bcf7285bb0 100644
--- a/core/res/res/values-night/values.xml
+++ b/core/res/res/values-night/values.xml
@@ -30,7 +30,7 @@
<style name="Theme.DeviceDefault.QuickSettings.Dialog" parent="Theme.DeviceDefault.Dialog" />
<style name="TextAppearance.Material.Notification">
- <item name="textColor">?attr/textColorPrimary</item>
+ <item name="textColor">@color/notification_secondary_text_color_dark</item>
<item name="textSize">@dimen/notification_text_size</item>
</style>
</resources> \ No newline at end of file
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 69bb20cf9c1e..735e122444ef 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3564,6 +3564,16 @@
<attr name="__removed2" format="boolean" />
<!-- Specifies whether the IME supports showing inline suggestions. -->
<attr name="supportsInlineSuggestions" format="boolean" />
+ <!-- Specify one or more configuration changes that the IME will handle itself. If not
+ specified, the IME will be restarted if any of these configuration changes happen in
+ the system. Otherwise, the IME will remain running and its
+ {@link android.inputmethodservice.InputMethodService#onConfigurationChanged}
+ method is called with the new configuration.
+ <p>Note that all of these configuration changes can impact the
+ resource values seen by the application, so you will generally need
+ to re-retrieve all resources (including view layouts, drawables, etc)
+ to correctly handle any configuration change.-->
+ <attr name="configChanges" />
</declare-styleable>
<!-- This is the subtype of InputMethod. Subtype can describe locales (for example, en_US and
@@ -4117,6 +4127,94 @@
user's time zone. Please refer to {@link java.util.TimeZone} for more
information about time zone ids. -->
<attr name="timeZone" format="string"/>
+ <!-- Tint to apply to the dial graphic. -->
+ <attr name="dialTint" format="color" />
+ <!-- Blending mode used to apply the dial graphic tint. -->
+ <attr name="dialTintMode">
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and drawable color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
+ </attr>
+ <!-- Tint to apply to the hour hand graphic. -->
+ <attr name="hand_hourTint" format="color" />
+ <!-- Blending mode used to apply the hour hand graphic tint. -->
+ <attr name="hand_hourTintMode">
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and drawable color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
+ </attr>
+ <!-- Tint to apply to the minute hand graphic. -->
+ <attr name="hand_minuteTint" format="color" />
+ <!-- Blending mode used to apply the minute hand graphic tint. -->
+ <attr name="hand_minuteTintMode">
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and drawable color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
+ </attr>
+ <!-- Tint to apply to the second hand graphic. -->
+ <attr name="hand_secondTint" format="color" />
+ <!-- Blending mode used to apply the second hand graphic tint. -->
+ <attr name="hand_secondTintMode">
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and drawable color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
+ </attr>
</declare-styleable>
<declare-styleable name="Button">
</declare-styleable>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 0ae6a76e2a60..45e11ba9820e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1893,6 +1893,11 @@
<!-- User data will remain unchanged during rollback. -->
<enum name="retain" value="2" />
</attr>
+
+ <!-- Applications can set this attribute to an xml resource within their app where they
+ specified the rules determining which files and directories can be copied from the device
+ as part of backup or transfer operations. -->
+ <attr name="dataExtractionRules" format="reference"/>
</declare-styleable>
<!-- An attribution is a logical part of an app and is identified by a tag.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9a917b72a5fd..592a3a1ff083 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1173,6 +1173,9 @@
<!-- Default value for LED off time when the battery is low on charge in miliseconds -->
<integer name="config_notificationsBatteryLedOff">2875</integer>
+ <!-- If true, only colorized CallStyle notifications will apply custom colors -->
+ <bool name="config_callNotificationActionColorsRequireColorized">true</bool>
+
<!-- Number of notifications to keep in the notification service historical archive -->
<integer name="config_notificationServiceArchiveSize">100</integer>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 1ca54985dfbc..695a831faf97 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -271,11 +271,8 @@
<!-- The top margin before the notification progress bar. -->
<dimen name="notification_progress_margin_top">8dp</dimen>
- <!-- height of the notification header when the notification is alone (minimized / groups) -->
- <dimen name="notification_header_solo_height">48dp</dimen>
-
- <!-- height of the notification header when in a "big" layout -->
- <dimen name="notification_header_big_height">56dp</dimen>
+ <!-- height of the notification header -->
+ <dimen name="notification_header_height">56dp</dimen>
<!-- The height of the background for a notification header on a group -->
<dimen name="notification_header_background_height">49.5dp</dimen>
@@ -365,7 +362,7 @@
<dimen name="media_notification_expanded_image_margin_bottom">20dp</dimen>
<!-- The absolute height for the header in a media notification. -->
- <dimen name="media_notification_header_height">@dimen/notification_header_big_height</dimen>
+ <dimen name="media_notification_header_height">@dimen/notification_header_height</dimen>
<!-- The margin of the content to an image-->
<dimen name="notification_content_image_margin_end">8dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a1ea61c447c0..9b2573f3d62f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3076,6 +3076,15 @@
<public name="maxResizeHeight" />
<public name="targetCellWidth" />
<public name="targetCellHeight" />
+ <public name="dialTint"/>
+ <public name="dialTintMode"/>
+ <public name="hand_hourTint"/>
+ <public name="hand_hourTintMode"/>
+ <public name="hand_minuteTint"/>
+ <public name="hand_minuteTintMode"/>
+ <public name="hand_secondTint"/>
+ <public name="hand_secondTintMode"/>
+ <public name="dataExtractionRules"/>
</public-group>
<public-group type="drawable" first-id="0x010800b5">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e73d6e3af3cb..29b8e6e08947 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2286,6 +2286,7 @@
<java-symbol type="string" name="config_wifi_tether_enable" />
<java-symbol type="bool" name="config_intrusiveNotificationLed" />
<java-symbol type="bool" name="config_notificationBadging" />
+ <java-symbol type="bool" name="config_callNotificationActionColorsRequireColorized" />
<java-symbol type="dimen" name="preference_fragment_padding_bottom" />
<java-symbol type="dimen" name="preference_fragment_padding_side" />
<java-symbol type="drawable" name="expander_ic_maximized" />
@@ -4203,6 +4204,4 @@
<java-symbol type="bool" name="config_telephony5gNonStandalone" />
<java-symbol type="bool" name="config_voice_data_sms_auto_fallback" />
-
- <java-symbol type="bool" name="config_enableOneHandedKeyguard" />
</resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index e7e049da18c9..16d720b891e2 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -238,6 +238,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -271,6 +273,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -306,6 +310,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -340,6 +346,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -417,6 +425,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -449,6 +459,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -482,6 +494,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -531,6 +545,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -565,6 +581,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -597,6 +615,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -631,6 +651,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -664,6 +686,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -697,6 +721,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -730,6 +756,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -763,6 +791,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -800,6 +830,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -834,6 +866,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -865,6 +899,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -1069,6 +1105,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1101,6 +1139,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1134,6 +1174,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1169,6 +1211,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1203,6 +1247,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1281,6 +1327,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1316,6 +1364,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1352,6 +1402,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1426,6 +1478,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1463,6 +1517,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1498,6 +1554,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1532,6 +1590,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1565,6 +1625,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1598,6 +1660,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1629,6 +1693,8 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1750,6 +1816,8 @@ easier.
<item name="colorSecondary">@color/secondary_device_default_settings</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
@@ -1782,6 +1850,8 @@ easier.
<item name="colorSecondary">@color/secondary_device_default_settings</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1824,6 +1894,8 @@ easier.
<item name="colorSecondary">@color/secondary_device_default_settings</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
@@ -1859,6 +1931,8 @@ easier.
<item name="colorSecondary">@color/secondary_device_default_settings</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
diff --git a/core/tests/GameManagerTests/Android.bp b/core/tests/GameManagerTests/Android.bp
index e1787762e067..2789e9f316d1 100644
--- a/core/tests/GameManagerTests/Android.bp
+++ b/core/tests/GameManagerTests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test {
name: "FrameworksCoreGameManagerTests",
// Include all test java files
diff --git a/core/tests/batterystatstests/BatteryStatsLoadTests/Android.bp b/core/tests/batterystatstests/BatteryStatsLoadTests/Android.bp
index ade97b81e775..1c0ea839ec02 100644
--- a/core/tests/batterystatstests/BatteryStatsLoadTests/Android.bp
+++ b/core/tests/batterystatstests/BatteryStatsLoadTests/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test {
name: "BatteryStatsLoadTests",
srcs: ["src/**/*.java"],
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/Android.bp b/core/tests/batterystatstests/BatteryStatsViewer/Android.bp
index 1e0498be5800..c2e7d81cb283 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/Android.bp
+++ b/core/tests/batterystatstests/BatteryStatsViewer/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test {
name: "BatteryStatsViewer",
srcs: ["src/**/*.java"],
diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java b/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java
new file mode 100644
index 000000000000..412b36713fa2
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input;
+
+import static android.hardware.lights.LightsRequest.Builder;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
+import android.hardware.lights.LightsManager;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+import android.util.ArrayMap;
+import android.view.InputDevice;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for {@link InputDeviceLightsManager}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:InputDeviceLightsManagerTest
+ */
+@Presubmit
+@RunWith(MockitoJUnitRunner.class)
+public class InputDeviceLightsManagerTest {
+ private static final String TAG = "InputDeviceLightsManagerTest";
+
+ private static final int DEVICE_ID = 1000;
+ private static final int PLAYER_ID = 3;
+
+ @Rule public final MockitoRule mockito = MockitoJUnit.rule();
+
+ private InputManager mInputManager;
+
+ @Mock private IInputManager mIInputManagerMock;
+
+ @Before
+ public void setUp() throws Exception {
+ when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{DEVICE_ID});
+
+ when(mIInputManagerMock.getInputDevice(eq(DEVICE_ID))).thenReturn(
+ createInputDevice(DEVICE_ID));
+
+ mInputManager = InputManager.resetInstance(mIInputManagerMock);
+
+ ArrayMap<Integer, LightState> lightStatesById = new ArrayMap<>();
+ doAnswer(invocation -> {
+ final int[] lightIds = (int[]) invocation.getArguments()[1];
+ final LightState[] lightStates =
+ (LightState[]) invocation.getArguments()[2];
+ for (int i = 0; i < lightIds.length; i++) {
+ lightStatesById.put(lightIds[i], lightStates[i]);
+ }
+ return null;
+ }).when(mIInputManagerMock).setLightStates(eq(DEVICE_ID),
+ any(int[].class), any(LightState[].class), any(IBinder.class));
+
+ doAnswer(invocation -> {
+ int lightId = (int) invocation.getArguments()[1];
+ if (lightStatesById.containsKey(lightId)) {
+ return lightStatesById.get(lightId);
+ }
+ return new LightState(0);
+ }).when(mIInputManagerMock).getLightState(eq(DEVICE_ID), anyInt());
+ }
+
+ @After
+ public void tearDown() {
+ InputManager.clearInstance();
+ }
+
+ private InputDevice createInputDevice(int id) {
+ return new InputDevice(id, 0 /* generation */, 0 /* controllerNumber */, "name",
+ 0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */,
+ 0 /* sources */, 0 /* keyboardType */, null /* keyCharacterMap */,
+ false /* hasVibrator */, false /* hasMicrophone */, false /* hasButtonUnderpad */,
+ false /* hasSensor */, false /* hasBattery */);
+ }
+
+ private void mockLights(Light[] lights) throws Exception {
+ // Mock the Lights returned form InputManagerService
+ when(mIInputManagerMock.getLights(eq(DEVICE_ID))).thenReturn(
+ new ArrayList(Arrays.asList(lights)));
+ }
+
+ @Test
+ public void testGetInputDeviceLights() throws Exception {
+ InputDevice device = mInputManager.getInputDevice(DEVICE_ID);
+ assertNotNull(device);
+
+ Light[] mockedLights = {
+ new Light(1 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_SINGLE),
+ new Light(2 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_RGB),
+ new Light(3 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_PLAYER_ID)
+ };
+ mockLights(mockedLights);
+
+ LightsManager lightsManager = device.getLightsManager();
+ List<Light> lights = lightsManager.getLights();
+ verify(mIInputManagerMock).getLights(eq(DEVICE_ID));
+ assertEquals(lights, Arrays.asList(mockedLights));
+ }
+
+ @Test
+ public void testControlMultipleLights() throws Exception {
+ InputDevice device = mInputManager.getInputDevice(DEVICE_ID);
+ assertNotNull(device);
+
+ Light[] mockedLights = {
+ new Light(1 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_RGB),
+ new Light(2 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_RGB),
+ new Light(3 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_RGB),
+ new Light(4 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_RGB)
+ };
+ mockLights(mockedLights);
+
+ LightsManager lightsManager = device.getLightsManager();
+ List<Light> lightList = lightsManager.getLights();
+ LightState[] states = new LightState[]{new LightState(0xf1), new LightState(0xf2),
+ new LightState(0xf3)};
+ // Open a session to request turn 3/4 lights on:
+ LightsManager.LightsSession session = lightsManager.openSession();
+ session.requestLights(new Builder()
+ .addLight(lightsManager.getLights().get(0), states[0])
+ .addLight(lightsManager.getLights().get(1), states[1])
+ .addLight(lightsManager.getLights().get(2), states[2])
+ .build());
+ IBinder token = session.getToken();
+
+ verify(mIInputManagerMock).openLightSession(eq(DEVICE_ID),
+ any(String.class), eq(token));
+ verify(mIInputManagerMock).setLightStates(eq(DEVICE_ID), eq(new int[]{1, 2, 3}),
+ eq(states), eq(token));
+
+ // Then all 3 should turn on.
+ assertThat(lightsManager.getLightState(lightsManager.getLights().get(0)).getColor())
+ .isEqualTo(0xf1);
+ assertThat(lightsManager.getLightState(lightsManager.getLights().get(1)).getColor())
+ .isEqualTo(0xf2);
+ assertThat(lightsManager.getLightState(lightsManager.getLights().get(2)).getColor())
+ .isEqualTo(0xf3);
+
+ // And the 4th should remain off.
+ assertThat(lightsManager.getLightState(lightsManager.getLights().get(3)).getColor())
+ .isEqualTo(0x00);
+
+ // close session
+ session.close();
+ verify(mIInputManagerMock).closeLightSession(eq(DEVICE_ID), eq(token));
+ }
+
+ @Test
+ public void testControlPlayerIdLight() throws Exception {
+ InputDevice device = mInputManager.getInputDevice(DEVICE_ID);
+ assertNotNull(device);
+
+ Light[] mockedLights = {
+ new Light(1 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_PLAYER_ID),
+ new Light(2 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_SINGLE),
+ new Light(3 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_RGB),
+ };
+ mockLights(mockedLights);
+
+ LightsManager lightsManager = device.getLightsManager();
+ List<Light> lightList = lightsManager.getLights();
+ LightState[] states = new LightState[]{new LightState(0xf1, PLAYER_ID)};
+ // Open a session to request set Player ID light:
+ LightsManager.LightsSession session = lightsManager.openSession();
+ session.requestLights(new Builder()
+ .addLight(lightsManager.getLights().get(0), states[0])
+ .build());
+ IBinder token = session.getToken();
+
+ verify(mIInputManagerMock).openLightSession(eq(DEVICE_ID),
+ any(String.class), eq(token));
+ verify(mIInputManagerMock).setLightStates(eq(DEVICE_ID), eq(new int[]{1}),
+ eq(states), eq(token));
+
+ // Verify the light state
+ assertThat(lightsManager.getLightState(lightsManager.getLights().get(0)).getColor())
+ .isEqualTo(0xf1);
+ assertThat(lightsManager.getLightState(lightsManager.getLights().get(0)).getPlayerId())
+ .isEqualTo(PLAYER_ID);
+
+ // close session
+ session.close();
+ verify(mIInputManagerMock).closeLightSession(eq(DEVICE_ID), eq(token));
+ }
+}
diff --git a/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java b/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java
new file mode 100644
index 000000000000..890614982ba5
--- /dev/null
+++ b/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.inputmethodservice;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+
+import static junit.framework.Assert.assertFalse;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ServiceTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeoutException;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputMethodServiceTest {
+ private InputMethodService mService;
+ private Context mContext;
+ @Rule
+ public final ServiceTestRule serviceRule = new ServiceTestRule();
+
+ @Before
+ public void setUp() throws TimeoutException {
+ mContext = getInstrumentation().getContext();
+ mService = new InputMethodService();
+ }
+
+ @Test
+ public void testShouldImeRestartForConfig() throws Exception {
+ // Make sure we preserve Pre-S behavior i.e. Service restarts.
+ mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.R;
+ Configuration config = mContext.getResources().getConfiguration();
+ mService.setLastKnownConfig(config);
+ assertTrue("IME should restart for Pre-S",
+ mService.shouldImeRestartForConfig(config));
+
+ // IME shouldn't restart on targetSdk S+ (with no config changes).
+ mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.S;
+ assertFalse("IME shouldn't restart for S+",
+ mService.shouldImeRestartForConfig(config));
+
+ // Screen density changed but IME doesn't handle congfigChanges
+ config.densityDpi = 99;
+ assertTrue("IME should restart for unhandled configChanges",
+ mService.shouldImeRestartForConfig(config));
+
+ // opt-in IME to handle config changes.
+ mService.setHandledConfigChanges(ActivityInfo.CONFIG_DENSITY);
+ assertFalse("IME shouldn't restart for S+ since it handles configChanges",
+ mService.shouldImeRestartForConfig(config));
+ }
+}
diff --git a/core/tests/coretests/src/android/util/RotationUtilsTest.java b/core/tests/coretests/src/android/util/RotationUtilsTest.java
new file mode 100644
index 000000000000..5dbe03e8b42b
--- /dev/null
+++ b/core/tests/coretests/src/android/util/RotationUtilsTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import static android.util.RotationUtils.rotateBounds;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.Rect;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link RotationUtils}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:RotationUtilsTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RotationUtilsTest {
+
+ @Test
+ public void testRotateBounds() {
+ Rect testParent = new Rect(0, 0, 1000, 600);
+ Rect testInner = new Rect(40, 20, 120, 80);
+
+ Rect testResult = new Rect(testInner);
+ rotateBounds(testResult, testParent, ROTATION_90);
+ assertEquals(new Rect(20, 880, 80, 960), testResult);
+
+ testResult.set(testInner);
+ rotateBounds(testResult, testParent, ROTATION_180);
+ assertEquals(new Rect(880, 520, 960, 580), testResult);
+
+ testResult.set(testInner);
+ rotateBounds(testResult, testParent, ROTATION_270);
+ assertEquals(new Rect(520, 40, 580, 120), testResult);
+ }
+}
diff --git a/core/tests/coretests/src/android/view/OWNERS b/core/tests/coretests/src/android/view/OWNERS
index 5031ff913e6d..80165f065995 100644
--- a/core/tests/coretests/src/android/view/OWNERS
+++ b/core/tests/coretests/src/android/view/OWNERS
@@ -1,7 +1,7 @@
# Input
-per-file *MotionEventTest.* = michaelwr@google.com, svv@google.com
-per-file *KeyEventTest.* = michaelwr@google.com, svv@google.com
-per-file VelocityTest.java = michaelwr@google.com, svv@google.com
+per-file *MotionEventTest.* = file:/services/core/java/com/android/server/input/OWNERS
+per-file *KeyEventTest.* = file:/services/core/java/com/android/server/input/OWNERS
+per-file VelocityTest.java = file:/services/core/java/com/android/server/input/OWNERS
# WindowManager
per-file *Display* = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java b/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java
new file mode 100644
index 000000000000..36104cf0f71d
--- /dev/null
+++ b/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+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;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class SurfaceControlFpsListenerTest {
+
+ @Test
+ public void registersAndUnregisters() {
+
+ SurfaceControlFpsListener listener = new SurfaceControlFpsListener() {
+ @Override
+ public void onFpsReported(float fps) {
+ // Ignore
+ }
+ };
+
+ listener.register(new SurfaceControl());
+
+ listener.unregister();
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
index 10aaf317fb49..9cb7876b3e5a 100644
--- a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
@@ -105,7 +105,8 @@ public class FrameTrackerTest {
mTracker = Mockito.spy(
new FrameTracker(session, handler, mRenderer, mViewRootWrapper,
mSurfaceControlWrapper, mChoreographer, mWrapper,
- /*traceThresholdMissedFrames=*/ 1, /*traceThresholdFrameTimeMillis=*/ -1));
+ /*traceThresholdMissedFrames=*/ 1, /*traceThresholdFrameTimeMillis=*/ -1,
+ null));
doNothing().when(mTracker).triggerPerfetto();
}
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
index c4c475b6a0e9..8f4948c02a74 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -96,7 +96,7 @@ public class InteractionJankMonitorTest {
new ViewRootWrapper(mView.getViewRootImpl()), new SurfaceControlWrapper(),
mock(FrameTracker.ChoreographerWrapper.class),
new FrameMetricsWrapper(), /*traceThresholdMissedFrames=*/ 1,
- /*traceThresholdFrameTimeMillis=*/ -1));
+ /*traceThresholdFrameTimeMillis=*/ -1, null));
doReturn(tracker).when(monitor).createFrameTracker(any(), any());
// Simulate a trace session and see if begin / end are invoked.
@@ -123,21 +123,12 @@ public class InteractionJankMonitorTest {
@Test
public void testCheckInitState() {
InteractionJankMonitor monitor = new InteractionJankMonitor(mWorker);
+ View view = new View(mActivity);
+ assertThat(view.isAttachedToWindow()).isFalse();
- // Should return false if invoking begin / end without init invocation.
- assertThat(monitor.begin(mView, CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isFalse();
+ // Should return false if the view passed in is not attached to window yet.
+ assertThat(monitor.begin(view, CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isFalse();
assertThat(monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isFalse();
-
- // Everything should be fine if invoking init first.
- boolean thrown = false;
- try {
- assertThat(monitor.begin(mView, CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isTrue();
- assertThat(monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isTrue();
- } catch (Exception ex) {
- thrown = true;
- } finally {
- assertThat(thrown).isFalse();
- }
}
@Test
@@ -152,7 +143,7 @@ public class InteractionJankMonitorTest {
new ViewRootWrapper(mView.getViewRootImpl()), new SurfaceControlWrapper(),
mock(FrameTracker.ChoreographerWrapper.class),
new FrameMetricsWrapper(), /*traceThresholdMissedFrames=*/ 1,
- /*traceThresholdFrameTimeMillis=*/ -1));
+ /*traceThresholdFrameTimeMillis=*/ -1, null));
doReturn(tracker).when(monitor).createFrameTracker(any(), any());
assertThat(monitor.begin(mView, session.getCuj())).isTrue();
diff --git a/core/tests/devicestatetests/Android.bp b/core/tests/devicestatetests/Android.bp
index 409b77bc399e..f7b593264cda 100644
--- a/core/tests/devicestatetests/Android.bp
+++ b/core/tests/devicestatetests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test {
name: "FrameworksCoreDeviceStateManagerTests",
// Include all test java files
diff --git a/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp b/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp
index 42421ce0e9f3..3536c4088dd8 100644
--- a/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp
+++ b/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp
@@ -50,4 +50,5 @@ apex {
key: "com.android.overlaytest.overlaid.key",
apps: ["OverlayRemountedTest_Target"],
installable: false,
+ updatable: false,
}
diff --git a/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp b/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp
index 0b52dcc4fb85..f04140409bea 100644
--- a/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp
+++ b/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp
@@ -50,4 +50,5 @@ apex {
key: "com.android.overlaytest.overlay.key",
apps: ["OverlayRemountedTest_Overlay"],
installable: false,
+ updatable: false,
}
diff --git a/data/etc/car/com.google.android.car.networking.preferenceupdater.xml b/data/etc/car/com.google.android.car.networking.preferenceupdater.xml
index 489ce1b47ffa..cdeb8e48a59b 100644
--- a/data/etc/car/com.google.android.car.networking.preferenceupdater.xml
+++ b/data/etc/car/com.google.android.car.networking.preferenceupdater.xml
@@ -16,12 +16,21 @@
-->
<permissions>
<privapp-permissions package="com.google.android.car.networking.preferenceupdater">
- <permission name="android.permission.ACCESS_NETWORK_STATE"/>
+ <permission name="android.permission.ACCESS_NETWORK_STATE" />
<permission name="android.permission.ACCESS_WIFI_STATE"/>
<permission name="android.permission.ACTIVITY_EMBEDDING"/>
+ <permission name="android.permission.CHANGE_NETWORK_STATE" />
+ <permission name="android.permission.CONNECTIVITY_INTERNAL" />
+ <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
+ <permission name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERNCE" />
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
- <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
+ <permission name="android.permission.INTERNET" />
<permission name="android.permission.LOCATION_HARDWARE"/>
+ <permission name="android.permission.PACKAGE_USAGE_STATS" />
+ <permission name="android.permission.RECEIVE_BOOT_COMPLETED" />
+ <permission name="android.permission.WAKE_LOCK" />
+ <permission name="android.permission.WRITE_SETTINGS" />
+ <permission name="android.car.permission.CAR_DRIVING_STATE" />
</privapp-permissions>
</permissions>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 2db4c5d6bf2a..4f188cc03282 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -223,7 +223,7 @@
<alias name="sans-serif-condensed-medium" to="sans-serif-condensed" weight="500" />
<family name="serif">
- <font weight="400" style="normal">NotoSerif-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSerif.ttf</font>
<font weight="700" style="normal">NotoSerif-Bold.ttf</font>
<font weight="400" style="italic">NotoSerif-Italic.ttf</font>
<font weight="700" style="italic">NotoSerif-BoldItalic.ttf</font>
@@ -275,144 +275,144 @@
<!-- fallback fonts -->
<family lang="und-Arab" variant="elegant">
- <font weight="400" style="normal">NotoNaskhArabic-Regular.ttf</font>
+ <font weight="400" style="normal">NotoNaskhArabic.ttf</font>
<font weight="700" style="normal">NotoNaskhArabic-Bold.ttf</font>
</family>
<family lang="und-Arab" variant="compact">
- <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font>
+ <font weight="400" style="normal">NotoNaskhArabicUI.ttf</font>
<font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
</family>
<family lang="und-Ethi">
- <font weight="400" style="normal">NotoSansEthiopic-VF.ttf
+ <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansEthiopic-VF.ttf
+ <font weight="500" style="normal">NotoSansEthiopic-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansEthiopic-VF.ttf
+ <font weight="600" style="normal">NotoSansEthiopic-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansEthiopic-VF.ttf
+ <font weight="700" style="normal">NotoSansEthiopic-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
- <font weight="400" style="normal" fallbackFor="serif">NotoSerifEthiopic-VF.ttf
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifEthiopic-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" fallbackFor="serif">NotoSerifEthiopic-VF.ttf
+ <font weight="500" style="normal" fallbackFor="serif">NotoSerifEthiopic-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" fallbackFor="serif">NotoSerifEthiopic-VF.ttf
+ <font weight="600" style="normal" fallbackFor="serif">NotoSerifEthiopic-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" fallbackFor="serif">NotoSerifEthiopic-VF.ttf
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifEthiopic-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Hebr">
- <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansHebrew.ttf</font>
<font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
<font weight="400" style="normal" fallbackFor="serif">NotoSerifHebrew-Regular.ttf</font>
<font weight="700" style="normal" fallbackFor="serif">NotoSerifHebrew-Bold.ttf</font>
</family>
<family lang="und-Thai" variant="elegant">
- <font weight="400" style="normal">NotoSansThai-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansThai.ttf</font>
<font weight="700" style="normal">NotoSansThai-Bold.ttf</font>
- <font weight="400" style="normal" fallbackFor="serif">NotoSerifThai-Regular.ttf</font>
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifThai.ttf</font>
<font weight="700" style="normal" fallbackFor="serif">NotoSerifThai-Bold.ttf</font>
</family>
<family lang="und-Thai" variant="compact">
- <font weight="400" style="normal">NotoSansThaiUI-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansThaiUI.ttf</font>
<font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font>
</family>
<family lang="und-Armn">
- <font weight="400" style="normal">NotoSansArmenian-VF.ttf
+ <font weight="400" style="normal">NotoSansArmenian-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansArmenian-VF.ttf
+ <font weight="500" style="normal">NotoSansArmenian-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansArmenian-VF.ttf
+ <font weight="600" style="normal">NotoSansArmenian-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansArmenian-VF.ttf
+ <font weight="700" style="normal">NotoSansArmenian-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
- <font weight="400" style="normal" fallbackFor="serif">NotoSerifArmenian-VF.ttf
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifArmenian-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" fallbackFor="serif">NotoSerifArmenian-VF.ttf
+ <font weight="500" style="normal" fallbackFor="serif">NotoSerifArmenian-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" fallbackFor="serif">NotoSerifArmenian-VF.ttf
+ <font weight="600" style="normal" fallbackFor="serif">NotoSerifArmenian-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" fallbackFor="serif">NotoSerifArmenian-VF.ttf
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifArmenian-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Geor,und-Geok">
- <font weight="400" style="normal">NotoSansGeorgian-VF.ttf
+ <font weight="400" style="normal">NotoSansGeorgian-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansGeorgian-VF.ttf
+ <font weight="500" style="normal">NotoSansGeorgian-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansGeorgian-VF.ttf
+ <font weight="600" style="normal">NotoSansGeorgian-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansGeorgian-VF.ttf
+ <font weight="700" style="normal">NotoSansGeorgian-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
- <font weight="400" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
+ <font weight="500" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
+ <font weight="600" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Deva" variant="elegant">
- <font weight="400" style="normal">NotoSansDevanagari-VF.ttf
+ <font weight="400" style="normal">NotoSansDevanagari-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansDevanagari-VF.ttf
+ <font weight="500" style="normal">NotoSansDevanagari-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansDevanagari-VF.ttf
+ <font weight="600" style="normal">NotoSansDevanagari-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansDevanagari-VF.ttf
+ <font weight="700" style="normal">NotoSansDevanagari-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
- <font weight="400" style="normal" fallbackFor="serif">NotoSerifDevanagari-VF.ttf
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifDevanagari-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" fallbackFor="serif">NotoSerifDevanagari-VF.ttf
+ <font weight="500" style="normal" fallbackFor="serif">NotoSerifDevanagari-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" fallbackFor="serif">NotoSerifDevanagari-VF.ttf
+ <font weight="600" style="normal" fallbackFor="serif">NotoSerifDevanagari-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" fallbackFor="serif">NotoSerifDevanagari-VF.ttf
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifDevanagari-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Deva" variant="compact">
- <font weight="400" style="normal">NotoSansDevanagariUI-VF.ttf
+ <font weight="400" style="normal">NotoSansDevanagariUI-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansDevanagariUI-VF.ttf
+ <font weight="500" style="normal">NotoSansDevanagariUI-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansDevanagariUI-VF.ttf
+ <font weight="600" style="normal">NotoSansDevanagariUI-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansDevanagariUI-VF.ttf
+ <font weight="700" style="normal">NotoSansDevanagariUI-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
@@ -421,347 +421,347 @@
danda characters.
-->
<family lang="und-Gujr" variant="elegant">
- <font weight="400" style="normal">NotoSansGujarati-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansGujarati.ttf</font>
<font weight="700" style="normal">NotoSansGujarati-Bold.ttf</font>
- <font weight="400" style="normal" fallbackFor="serif">NotoSerifGujarati-VF.ttf
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifGujarati-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" fallbackFor="serif">NotoSerifGujarati-VF.ttf
+ <font weight="500" style="normal" fallbackFor="serif">NotoSerifGujarati-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" fallbackFor="serif">NotoSerifGujarati-VF.ttf
+ <font weight="600" style="normal" fallbackFor="serif">NotoSerifGujarati-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" fallbackFor="serif">NotoSerifGujarati-VF.ttf
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifGujarati-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Gujr" variant="compact">
- <font weight="400" style="normal">NotoSansGujaratiUI-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansGujaratiUI.ttf</font>
<font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font>
</family>
<family lang="und-Guru" variant="elegant">
- <font weight="400" style="normal">NotoSansGurmukhi-VF.ttf
+ <font weight="400" style="normal">NotoSansGurmukhi-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansGurmukhi-VF.ttf
+ <font weight="500" style="normal">NotoSansGurmukhi-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansGurmukhi-VF.ttf
+ <font weight="600" style="normal">NotoSansGurmukhi-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansGurmukhi-VF.ttf
+ <font weight="700" style="normal">NotoSansGurmukhi-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
- <font weight="400" style="normal" fallbackFor="serif">NotoSerifGurmukhi-VF.ttf
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifGurmukhi-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" fallbackFor="serif">NotoSerifGurmukhi-VF.ttf
+ <font weight="500" style="normal" fallbackFor="serif">NotoSerifGurmukhi-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" fallbackFor="serif">NotoSerifGurmukhi-VF.ttf
+ <font weight="600" style="normal" fallbackFor="serif">NotoSerifGurmukhi-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" fallbackFor="serif">NotoSerifGurmukhi-VF.ttf
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifGurmukhi-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Guru" variant="compact">
- <font weight="400" style="normal">NotoSansGurmukhiUI-VF.ttf
+ <font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansGurmukhiUI-VF.ttf
+ <font weight="500" style="normal">NotoSansGurmukhiUI-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansGurmukhiUI-VF.ttf
+ <font weight="600" style="normal">NotoSansGurmukhiUI-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansGurmukhiUI-VF.ttf
+ <font weight="700" style="normal">NotoSansGurmukhiUI-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Taml" variant="elegant">
- <font weight="400" style="normal">NotoSansTamil-VF.ttf
+ <font weight="400" style="normal">NotoSansTamil-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansTamil-VF.ttf
+ <font weight="500" style="normal">NotoSansTamil-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansTamil-VF.ttf
+ <font weight="600" style="normal">NotoSansTamil-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansTamil-VF.ttf
+ <font weight="700" style="normal">NotoSansTamil-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
- <font weight="400" style="normal" fallbackFor="serif">NotoSerifTamil-VF.ttf
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifTamil-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" fallbackFor="serif">NotoSerifTamil-VF.ttf
+ <font weight="500" style="normal" fallbackFor="serif">NotoSerifTamil-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" fallbackFor="serif">NotoSerifTamil-VF.ttf
+ <font weight="600" style="normal" fallbackFor="serif">NotoSerifTamil-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" fallbackFor="serif">NotoSerifTamil-VF.ttf
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifTamil-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Taml" variant="compact">
- <font weight="400" style="normal">NotoSansTamilUI-VF.ttf
+ <font weight="400" style="normal">NotoSansTamilUI-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansTamilUI-VF.ttf
+ <font weight="500" style="normal">NotoSansTamilUI-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansTamilUI-VF.ttf
+ <font weight="600" style="normal">NotoSansTamilUI-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansTamilUI-VF.ttf
+ <font weight="700" style="normal">NotoSansTamilUI-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Mlym" variant="elegant">
- <font weight="400" style="normal">NotoSansMalayalam-VF.ttf
+ <font weight="400" style="normal">NotoSansMalayalam-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansMalayalam-VF.ttf
+ <font weight="500" style="normal">NotoSansMalayalam-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansMalayalam-VF.ttf
+ <font weight="600" style="normal">NotoSansMalayalam-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansMalayalam-VF.ttf
+ <font weight="700" style="normal">NotoSansMalayalam-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
- <font weight="400" style="normal" fallbackFor="serif">NotoSerifMalayalam-VF.ttf
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifMalayalam-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" fallbackFor="serif">NotoSerifMalayalam-VF.ttf
+ <font weight="500" style="normal" fallbackFor="serif">NotoSerifMalayalam-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" fallbackFor="serif">NotoSerifMalayalam-VF.ttf
+ <font weight="600" style="normal" fallbackFor="serif">NotoSerifMalayalam-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" fallbackFor="serif">NotoSerifMalayalam-VF.ttf
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifMalayalam-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Mlym" variant="compact">
- <font weight="400" style="normal">NotoSansMalayalamUI-VF.ttf
+ <font weight="400" style="normal">NotoSansMalayalamUI-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansMalayalamUI-VF.ttf
+ <font weight="500" style="normal">NotoSansMalayalamUI-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansMalayalamUI-VF.ttf
+ <font weight="600" style="normal">NotoSansMalayalamUI-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansMalayalamUI-VF.ttf
+ <font weight="700" style="normal">NotoSansMalayalamUI-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Beng" variant="elegant">
- <font weight="400" style="normal">NotoSansBengali-VF.ttf
+ <font weight="400" style="normal">NotoSansBengali-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansBengali-VF.ttf
+ <font weight="500" style="normal">NotoSansBengali-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansBengali-VF.ttf
+ <font weight="600" style="normal">NotoSansBengali-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansBengali-VF.ttf
+ <font weight="700" style="normal">NotoSansBengali-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
- <font weight="400" style="normal" fallbackFor="serif">NotoSerifBengali-VF.ttf
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifBengali-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" fallbackFor="serif">NotoSerifBengali-VF.ttf
+ <font weight="500" style="normal" fallbackFor="serif">NotoSerifBengali-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" fallbackFor="serif">NotoSerifBengali-VF.ttf
+ <font weight="600" style="normal" fallbackFor="serif">NotoSerifBengali-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" fallbackFor="serif">NotoSerifBengali-VF.ttf
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifBengali-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Beng" variant="compact">
- <font weight="400" style="normal">NotoSansBengaliUI-VF.ttf
+ <font weight="400" style="normal">NotoSansBengaliUI-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansBengaliUI-VF.ttf
+ <font weight="500" style="normal">NotoSansBengaliUI-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansBengaliUI-VF.ttf
+ <font weight="600" style="normal">NotoSansBengaliUI-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansBengaliUI-VF.ttf
+ <font weight="700" style="normal">NotoSansBengaliUI-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Telu" variant="elegant">
- <font weight="400" style="normal">NotoSansTelugu-VF.ttf
+ <font weight="400" style="normal">NotoSansTelugu-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansTelugu-VF.ttf
+ <font weight="500" style="normal">NotoSansTelugu-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansTelugu-VF.ttf
+ <font weight="600" style="normal">NotoSansTelugu-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansTelugu-VF.ttf
+ <font weight="700" style="normal">NotoSansTelugu-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
- <font weight="400" style="normal" fallbackFor="serif">NotoSerifTelugu-VF.ttf
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifTelugu-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" fallbackFor="serif">NotoSerifTelugu-VF.ttf
+ <font weight="500" style="normal" fallbackFor="serif">NotoSerifTelugu-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" fallbackFor="serif">NotoSerifTelugu-VF.ttf
+ <font weight="600" style="normal" fallbackFor="serif">NotoSerifTelugu-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" fallbackFor="serif">NotoSerifTelugu-VF.ttf
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifTelugu-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Telu" variant="compact">
- <font weight="400" style="normal">NotoSansTeluguUI-VF.ttf
+ <font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansTeluguUI-VF.ttf
+ <font weight="500" style="normal">NotoSansTeluguUI-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansTeluguUI-VF.ttf
+ <font weight="600" style="normal">NotoSansTeluguUI-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansTeluguUI-VF.ttf
+ <font weight="700" style="normal">NotoSansTeluguUI-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Knda" variant="elegant">
- <font weight="400" style="normal">NotoSansKannada-VF.ttf
+ <font weight="400" style="normal">NotoSansKannada-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansKannada-VF.ttf
+ <font weight="500" style="normal">NotoSansKannada-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansKannada-VF.ttf
+ <font weight="600" style="normal">NotoSansKannada-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansKannada-VF.ttf
+ <font weight="700" style="normal">NotoSansKannada-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
- <font weight="400" style="normal" fallbackFor="serif">NotoSerifKannada-VF.ttf
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifKannada-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" fallbackFor="serif">NotoSerifKannada-VF.ttf
+ <font weight="500" style="normal" fallbackFor="serif">NotoSerifKannada-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" fallbackFor="serif">NotoSerifKannada-VF.ttf
+ <font weight="600" style="normal" fallbackFor="serif">NotoSerifKannada-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" fallbackFor="serif">NotoSerifKannada-VF.ttf
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifKannada-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Knda" variant="compact">
- <font weight="400" style="normal">NotoSansKannadaUI-VF.ttf
+ <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansKannadaUI-VF.ttf
+ <font weight="500" style="normal">NotoSansKannadaUI-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansKannadaUI-VF.ttf
+ <font weight="600" style="normal">NotoSansKannadaUI-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansKannadaUI-VF.ttf
+ <font weight="700" style="normal">NotoSansKannadaUI-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Orya" variant="elegant">
- <font weight="400" style="normal">NotoSansOriya-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansOriya.ttf</font>
<font weight="700" style="normal">NotoSansOriya-Bold.ttf</font>
</family>
<family lang="und-Orya" variant="compact">
- <font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansOriyaUI.ttf</font>
<font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font>
</family>
<family lang="und-Sinh" variant="elegant">
- <font weight="400" style="normal">NotoSansSinhala-VF.ttf
+ <font weight="400" style="normal">NotoSansSinhala-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansSinhala-VF.ttf
+ <font weight="500" style="normal">NotoSansSinhala-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansSinhala-VF.ttf
+ <font weight="600" style="normal">NotoSansSinhala-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansSinhala-VF.ttf
+ <font weight="700" style="normal">NotoSansSinhala-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
- <font weight="400" style="normal" fallbackFor="serif">NotoSerifSinhala-VF.ttf
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifSinhala-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal" fallbackFor="serif">NotoSerifSinhala-VF.ttf
+ <font weight="500" style="normal" fallbackFor="serif">NotoSerifSinhala-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal" fallbackFor="serif">NotoSerifSinhala-VF.ttf
+ <font weight="600" style="normal" fallbackFor="serif">NotoSerifSinhala-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal" fallbackFor="serif">NotoSerifSinhala-VF.ttf
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifSinhala-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Sinh" variant="compact">
- <font weight="400" style="normal">NotoSansSinhalaUI-VF.ttf
+ <font weight="400" style="normal">NotoSansSinhalaUI-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansSinhalaUI-VF.ttf
+ <font weight="500" style="normal">NotoSansSinhalaUI-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansSinhalaUI-VF.ttf
+ <font weight="600" style="normal">NotoSansSinhalaUI-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansSinhalaUI-VF.ttf
+ <font weight="700" style="normal">NotoSansSinhalaUI-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Khmr" variant="elegant">
- <font weight="100" style="normal">NotoSansKhmer-VF.ttf
+ <font weight="100" style="normal">NotoSansKhmer-Regular.ttf
<axis tag="wdth" stylevalue="100.0"/>
<axis tag="wght" stylevalue="26.0"/>
</font>
- <font weight="200" style="normal">NotoSansKhmer-VF.ttf
+ <font weight="200" style="normal">NotoSansKhmer-Regular.ttf
<axis tag="wdth" stylevalue="100.0"/>
<axis tag="wght" stylevalue="39.0"/>
</font>
- <font weight="300" style="normal">NotoSansKhmer-VF.ttf
+ <font weight="300" style="normal">NotoSansKhmer-Regular.ttf
<axis tag="wdth" stylevalue="100.0"/>
<axis tag="wght" stylevalue="58.0"/>
</font>
- <font weight="400" style="normal">NotoSansKhmer-VF.ttf
+ <font weight="400" style="normal">NotoSansKhmer-Regular.ttf
<axis tag="wdth" stylevalue="100.0"/>
<axis tag="wght" stylevalue="90.0"/>
</font>
- <font weight="500" style="normal">NotoSansKhmer-VF.ttf
+ <font weight="500" style="normal">NotoSansKhmer-Regular.ttf
<axis tag="wdth" stylevalue="100.0"/>
<axis tag="wght" stylevalue="108.0"/>
</font>
- <font weight="600" style="normal">NotoSansKhmer-VF.ttf
+ <font weight="600" style="normal">NotoSansKhmer-Regular.ttf
<axis tag="wdth" stylevalue="100.0"/>
<axis tag="wght" stylevalue="128.0"/>
</font>
- <font weight="700" style="normal">NotoSansKhmer-VF.ttf
+ <font weight="700" style="normal">NotoSansKhmer-Regular.ttf
<axis tag="wdth" stylevalue="100.0"/>
<axis tag="wght" stylevalue="151.0"/>
</font>
- <font weight="800" style="normal">NotoSansKhmer-VF.ttf
+ <font weight="800" style="normal">NotoSansKhmer-Regular.ttf
<axis tag="wdth" stylevalue="100.0"/>
<axis tag="wght" stylevalue="169.0"/>
</font>
- <font weight="900" style="normal">NotoSansKhmer-VF.ttf
+ <font weight="900" style="normal">NotoSansKhmer-Regular.ttf
<axis tag="wdth" stylevalue="100.0"/>
<axis tag="wght" stylevalue="190.0"/>
</font>
@@ -769,17 +769,17 @@
<font weight="700" style="normal" fallbackFor="serif">NotoSerifKhmer-Bold.otf</font>
</family>
<family lang="und-Khmr" variant="compact">
- <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansKhmerUI.ttf</font>
<font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
</family>
<family lang="und-Laoo" variant="elegant">
- <font weight="400" style="normal">NotoSansLao-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansLao.ttf</font>
<font weight="700" style="normal">NotoSansLao-Bold.ttf</font>
- <font weight="400" style="normal" fallbackFor="serif">NotoSerifLao-Regular.ttf</font>
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifLao.ttf</font>
<font weight="700" style="normal" fallbackFor="serif">NotoSerifLao-Bold.ttf</font>
</family>
<family lang="und-Laoo" variant="compact">
- <font weight="400" style="normal">NotoSansLaoUI-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansLaoUI.ttf</font>
<font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
</family>
<family lang="und-Mymr" variant="elegant">
@@ -795,56 +795,56 @@
<font weight="700" style="normal">NotoSansMyanmarUI-Bold.otf</font>
</family>
<family lang="und-Thaa">
- <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansThaana.ttf</font>
<font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
</family>
<family lang="und-Cham">
- <font weight="400" style="normal">NotoSansCham-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansCham.ttf</font>
<font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
</family>
<family lang="und-Ahom">
<font weight="400" style="normal">NotoSansAhom-Regular.otf</font>
</family>
<family lang="und-Adlm">
- <font weight="400" style="normal">NotoSansAdlam-VF.ttf
+ <font weight="400" style="normal">NotoSansAdlam-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansAdlam-VF.ttf
+ <font weight="500" style="normal">NotoSansAdlam-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansAdlam-VF.ttf
+ <font weight="600" style="normal">NotoSansAdlam-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansAdlam-VF.ttf
+ <font weight="700" style="normal">NotoSansAdlam-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Avst">
- <font weight="400" style="normal">NotoSansAvestan-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansAvestan.ttf</font>
</family>
<family lang="und-Bali">
- <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansBalinese.ttf</font>
</family>
<family lang="und-Bamu">
- <font weight="400" style="normal">NotoSansBamum-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansBamum.ttf</font>
</family>
<family lang="und-Batk">
- <font weight="400" style="normal">NotoSansBatak-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansBatak.ttf</font>
</family>
<family lang="und-Brah">
- <font weight="400" style="normal">NotoSansBrahmi-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansBrahmi.ttf</font>
</family>
<family lang="und-Bugi">
- <font weight="400" style="normal">NotoSansBuginese-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansBuginese.ttf</font>
</family>
<family lang="und-Buhd">
- <font weight="400" style="normal">NotoSansBuhid-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansBuhid.ttf</font>
</family>
<family lang="und-Cans">
- <font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansCanadianAboriginal.ttf</font>
</family>
<family lang="und-Cari">
- <font weight="400" style="normal">NotoSansCarian-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansCarian.ttf</font>
</family>
<family lang="und-Cakm">
<font weight="400" style="normal">NotoSansChakma-Regular.otf</font>
@@ -853,164 +853,164 @@
<font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
</family>
<family lang="und-Copt">
- <font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansCoptic.ttf</font>
</family>
<family lang="und-Xsux">
- <font weight="400" style="normal">NotoSansCuneiform-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansCuneiform.ttf</font>
</family>
<family lang="und-Cprt">
- <font weight="400" style="normal">NotoSansCypriot-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansCypriot.ttf</font>
</family>
<family lang="und-Dsrt">
- <font weight="400" style="normal">NotoSansDeseret-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansDeseret.ttf</font>
</family>
<family lang="und-Egyp">
- <font weight="400" style="normal">NotoSansEgyptianHieroglyphs-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansEgyptianHieroglyphs.ttf</font>
</family>
<family lang="und-Elba">
<font weight="400" style="normal">NotoSansElbasan-Regular.otf</font>
</family>
<family lang="und-Glag">
- <font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansGlagolitic.ttf</font>
</family>
<family lang="und-Goth">
- <font weight="400" style="normal">NotoSansGothic-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansGothic.ttf</font>
</family>
<family lang="und-Hano">
- <font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansHanunoo.ttf</font>
</family>
<family lang="und-Armi">
- <font weight="400" style="normal">NotoSansImperialAramaic-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansImperialAramaic.ttf</font>
</family>
<family lang="und-Phli">
- <font weight="400" style="normal">NotoSansInscriptionalPahlavi-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansInscriptionalPahlavi.ttf</font>
</family>
<family lang="und-Prti">
- <font weight="400" style="normal">NotoSansInscriptionalParthian-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansInscriptionalParthian.ttf</font>
</family>
<family lang="und-Java">
<font weight="400" style="normal">NotoSansJavanese-Regular.otf</font>
</family>
<family lang="und-Kthi">
- <font weight="400" style="normal">NotoSansKaithi-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansKaithi.ttf</font>
</family>
<family lang="und-Kali">
- <font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansKayahLi.ttf</font>
</family>
<family lang="und-Khar">
- <font weight="400" style="normal">NotoSansKharoshthi-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansKharoshthi.ttf</font>
</family>
<family lang="und-Lepc">
- <font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansLepcha.ttf</font>
</family>
<family lang="und-Limb">
- <font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansLimbu.ttf</font>
</family>
<family lang="und-Linb">
- <font weight="400" style="normal">NotoSansLinearB-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansLinearB.ttf</font>
</family>
<family lang="und-Lisu">
- <font weight="400" style="normal">NotoSansLisu-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansLisu.ttf</font>
</family>
<family lang="und-Lyci">
- <font weight="400" style="normal">NotoSansLycian-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansLycian.ttf</font>
</family>
<family lang="und-Lydi">
- <font weight="400" style="normal">NotoSansLydian-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansLydian.ttf</font>
</family>
<family lang="und-Mand">
- <font weight="400" style="normal">NotoSansMandaic-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansMandaic.ttf</font>
</family>
<family lang="und-Mtei">
- <font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansMeeteiMayek.ttf</font>
</family>
<family lang="und-Talu">
- <font weight="400" style="normal">NotoSansNewTaiLue-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansNewTaiLue.ttf</font>
</family>
<family lang="und-Nkoo">
- <font weight="400" style="normal">NotoSansNKo-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansNKo.ttf</font>
</family>
<family lang="und-Ogam">
- <font weight="400" style="normal">NotoSansOgham-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansOgham.ttf</font>
</family>
<family lang="und-Olck">
- <font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansOlChiki.ttf</font>
</family>
<family lang="und-Ital">
- <font weight="400" style="normal">NotoSansOldItalic-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansOldItalic.ttf</font>
</family>
<family lang="und-Xpeo">
- <font weight="400" style="normal">NotoSansOldPersian-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansOldPersian.ttf</font>
</family>
<family lang="und-Sarb">
- <font weight="400" style="normal">NotoSansOldSouthArabian-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansOldSouthArabian.ttf</font>
</family>
<family lang="und-Orkh">
- <font weight="400" style="normal">NotoSansOldTurkic-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansOldTurkic.ttf</font>
</family>
<family lang="und-Osge">
<font weight="400" style="normal">NotoSansOsage-Regular.ttf</font>
</family>
<family lang="und-Osma">
- <font weight="400" style="normal">NotoSansOsmanya-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansOsmanya.ttf</font>
</family>
<family lang="und-Phnx">
- <font weight="400" style="normal">NotoSansPhoenician-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansPhoenician.ttf</font>
</family>
<family lang="und-Rjng">
- <font weight="400" style="normal">NotoSansRejang-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansRejang.ttf</font>
</family>
<family lang="und-Runr">
- <font weight="400" style="normal">NotoSansRunic-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansRunic.ttf</font>
</family>
<family lang="und-Samr">
- <font weight="400" style="normal">NotoSansSamaritan-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansSamaritan.ttf</font>
</family>
<family lang="und-Saur">
- <font weight="400" style="normal">NotoSansSaurashtra-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansSaurashtra.ttf</font>
</family>
<family lang="und-Shaw">
- <font weight="400" style="normal">NotoSansShavian-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansShavian.ttf</font>
</family>
<family lang="und-Sund">
- <font weight="400" style="normal">NotoSansSundanese-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansSundanese.ttf</font>
</family>
<family lang="und-Sylo">
- <font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansSylotiNagri.ttf</font>
</family>
<!-- Esrangela should precede Eastern and Western Syriac, since it's our default form. -->
<family lang="und-Syre">
- <font weight="400" style="normal">NotoSansSyriacEstrangela-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansSyriacEstrangela.ttf</font>
</family>
<family lang="und-Syrn">
- <font weight="400" style="normal">NotoSansSyriacEastern-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansSyriacEastern.ttf</font>
</family>
<family lang="und-Syrj">
- <font weight="400" style="normal">NotoSansSyriacWestern-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansSyriacWestern.ttf</font>
</family>
<family lang="und-Tglg">
- <font weight="400" style="normal">NotoSansTagalog-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansTagalog.ttf</font>
</family>
<family lang="und-Tagb">
- <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansTagbanwa.ttf</font>
</family>
<family lang="und-Lana">
- <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansTaiTham.ttf</font>
</family>
<family lang="und-Tavt">
- <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansTaiViet.ttf</font>
</family>
<family lang="und-Tibt">
- <font weight="400" style="normal">NotoSerifTibetan-VF.ttf
+ <font weight="400" style="normal">NotoSerifTibetan-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSerifTibetan-VF.ttf
+ <font weight="500" style="normal">NotoSerifTibetan-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSerifTibetan-VF.ttf
+ <font weight="600" style="normal">NotoSerifTibetan-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSerifTibetan-VF.ttf
+ <font weight="700" style="normal">NotoSerifTibetan-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
@@ -1018,29 +1018,29 @@
<font weight="400" style="normal">NotoSansTifinagh-Regular.otf</font>
</family>
<family lang="und-Ugar">
- <font weight="400" style="normal">NotoSansUgaritic-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansUgaritic.ttf</font>
</family>
<family lang="und-Vaii">
- <font weight="400" style="normal">NotoSansVai-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansVai.ttf</font>
</family>
<family>
<font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
</family>
<family lang="zh-Hans">
- <font weight="400" style="normal" index="2">NotoSansCJK-Regular.ttc</font>
- <font weight="400" style="normal" index="2" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font>
+ <font weight="400" style="normal" index="2">NotoSansCJKjp-Regular.otc</font>
+ <font weight="400" style="normal" index="2" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
</family>
<family lang="zh-Hant,zh-Bopo">
- <font weight="400" style="normal" index="3">NotoSansCJK-Regular.ttc</font>
- <font weight="400" style="normal" index="3" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font>
+ <font weight="400" style="normal" index="3">NotoSansCJKjp-Regular.otc</font>
+ <font weight="400" style="normal" index="3" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
</family>
<family lang="ja">
- <font weight="400" style="normal" index="0">NotoSansCJK-Regular.ttc</font>
- <font weight="400" style="normal" index="0" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font>
+ <font weight="400" style="normal" index="0">NotoSansCJKjp-Regular.otc</font>
+ <font weight="400" style="normal" index="0" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
</family>
<family lang="ko">
- <font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font>
- <font weight="400" style="normal" index="1" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font>
+ <font weight="400" style="normal" index="1">NotoSansCJKjp-Regular.otc</font>
+ <font weight="400" style="normal" index="1" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
</family>
<family lang="und-Zsye">
<font weight="400" style="normal">NotoColorEmoji.ttf</font>
@@ -1053,16 +1053,16 @@
override the East Asian punctuation for Chinese.
-->
<family lang="und-Tale">
- <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansTaiLe.ttf</font>
</family>
<family lang="und-Yiii">
- <font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansYi.ttf</font>
</family>
<family lang="und-Mong">
- <font weight="400" style="normal">NotoSansMongolian-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansMongolian.ttf</font>
</family>
<family lang="und-Phag">
- <font weight="400" style="normal">NotoSansPhagsPa-Regular.ttf</font>
+ <font weight="400" style="normal">NotoSansPhagsPa.ttf</font>
</family>
<family lang="und-Hluw">
<font weight="400" style="normal">NotoSansAnatolianHieroglyphs-Regular.otf</font>
@@ -1152,72 +1152,72 @@
<font weight="400" style="normal">NotoSerifDogra-Regular.ttf</font>
</family>
<family lang="und-Medf">
- <font weight="400" style="normal">NotoSansMedefaidrin-VF.ttf
+ <font weight="400" style="normal">NotoSansMedefaidrin-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansMedefaidrin-VF.ttf
+ <font weight="500" style="normal">NotoSansMedefaidrin-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansMedefaidrin-VF.ttf
+ <font weight="600" style="normal">NotoSansMedefaidrin-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansMedefaidrin-VF.ttf
+ <font weight="700" style="normal">NotoSansMedefaidrin-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Soyo">
- <font weight="400" style="normal">NotoSansSoyombo-VF.ttf
+ <font weight="400" style="normal">NotoSansSoyombo-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansSoyombo-VF.ttf
+ <font weight="500" style="normal">NotoSansSoyombo-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansSoyombo-VF.ttf
+ <font weight="600" style="normal">NotoSansSoyombo-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansSoyombo-VF.ttf
+ <font weight="700" style="normal">NotoSansSoyombo-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Takr">
- <font weight="400" style="normal">NotoSansTakri-VF.ttf
+ <font weight="400" style="normal">NotoSansTakri-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSansTakri-VF.ttf
+ <font weight="500" style="normal">NotoSansTakri-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSansTakri-VF.ttf
+ <font weight="600" style="normal">NotoSansTakri-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSansTakri-VF.ttf
+ <font weight="700" style="normal">NotoSansTakri-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Hmnp">
- <font weight="400" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf
+ <font weight="400" style="normal">NotoSerifHmongNyiakeng-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf
+ <font weight="500" style="normal">NotoSerifHmongNyiakeng-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf
+ <font weight="600" style="normal">NotoSerifHmongNyiakeng-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf
+ <font weight="700" style="normal">NotoSerifHmongNyiakeng-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Yezi">
- <font weight="400" style="normal">NotoSerifYezidi-VF.ttf
+ <font weight="400" style="normal">NotoSerifYezidi-Regular.ttf
<axis tag="wght" stylevalue="400"/>
</font>
- <font weight="500" style="normal">NotoSerifYezidi-VF.ttf
+ <font weight="500" style="normal">NotoSerifYezidi-Regular.ttf
<axis tag="wght" stylevalue="500"/>
</font>
- <font weight="600" style="normal">NotoSerifYezidi-VF.ttf
+ <font weight="600" style="normal">NotoSerifYezidi-Regular.ttf
<axis tag="wght" stylevalue="600"/>
</font>
- <font weight="700" style="normal">NotoSerifYezidi-VF.ttf
+ <font weight="700" style="normal">NotoSerifYezidi-Regular.ttf
<axis tag="wght" stylevalue="700"/>
</font>
</family>
diff --git a/data/keyboards/OWNERS b/data/keyboards/OWNERS
index c4f6df824a39..0ce83507160c 100644
--- a/data/keyboards/OWNERS
+++ b/data/keyboards/OWNERS
@@ -1,5 +1,3 @@
set noparent
-michaelwr@google.com
-svv@google.com
-lzye@google.com
+include /services/core/java/com/android/server/input/OWNERS
diff --git a/data/keyboards/Vendor_057e_Product_2009.kl b/data/keyboards/Vendor_057e_Product_2009.kl
index 3c6b11e4640c..7491ee562b59 100644
--- a/data/keyboards/Vendor_057e_Product_2009.kl
+++ b/data/keyboards/Vendor_057e_Product_2009.kl
@@ -74,3 +74,11 @@ key 0x135 BUTTON_MODE
# Home key
key 0x13c HOME
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/graphics/java/android/graphics/FrameInfo.java b/graphics/java/android/graphics/FrameInfo.java
index d59abb5916a0..189be53a397f 100644
--- a/graphics/java/android/graphics/FrameInfo.java
+++ b/graphics/java/android/graphics/FrameInfo.java
@@ -69,28 +69,26 @@ public final class FrameInfo {
// animation & drawing system
public static final int VSYNC = 3;
- // The time of the oldest input event
- public static final int OLDEST_INPUT_EVENT = 4;
-
- // The time of the newest input event
- public static final int NEWEST_INPUT_EVENT = 5;
+ // The id of the input event that caused the current frame
+ public static final int INPUT_EVENT_ID = 4;
// When input event handling started
- public static final int HANDLE_INPUT_START = 6;
+ public static final int HANDLE_INPUT_START = 5;
// When animation evaluations started
- public static final int ANIMATION_START = 7;
+ public static final int ANIMATION_START = 6;
// When ViewRootImpl#performTraversals() started
- public static final int PERFORM_TRAVERSALS_START = 8;
+ public static final int PERFORM_TRAVERSALS_START = 7;
// When View:draw() started
- public static final int DRAW_START = 9;
+ public static final int DRAW_START = 8;
// When the frame needs to be ready by
- public static final int FRAME_DEADLINE = 10;
+ public static final int FRAME_DEADLINE = 9;
// Must be the last one
+ // This value must be in sync with `UI_THREAD_FRAME_INFO_SIZE` in FrameInfo.h
private static final int FRAME_INFO_SIZE = FRAME_DEADLINE + 1;
/** checkstyle */
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index f708298a2cbd..684eebe6ffde 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -37,8 +37,6 @@ interface IKeyChainService {
void setUserSelectable(String alias, boolean isUserSelectable);
int generateKeyPair(in String algorithm, in ParcelableKeyGenParameterSpec spec);
- int attestKey(in String alias, in byte[] challenge, in int[] idAttestationFlags,
- out KeymasterCertificateChain chain);
boolean setKeyPairCertificate(String alias, in byte[] userCert, in byte[] certChain);
// APIs used by CertInstaller and DevicePolicyManager
@@ -65,6 +63,7 @@ interface IKeyChainService {
AppUriAuthenticationPolicy getCredentialManagementAppPolicy();
String getPredefinedAliasForPackageAndUri(String packageName, in Uri uri);
void removeCredentialManagementApp();
+ boolean isCredentialManagementApp(String packageName);
// APIs used by KeyChainActivity
void setGrant(int uid, String alias, boolean value);
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 97819c56fd5a..65a81cd57f41 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -44,6 +44,8 @@ import android.os.UserManager;
import android.security.keystore.AndroidKeyStoreProvider;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
+import android.system.keystore2.Domain;
+import android.system.keystore2.KeyDescriptor;
import android.util.Log;
import com.android.org.conscrypt.TrustedCertificateStore;
@@ -421,6 +423,15 @@ public final class KeyChain {
* credentials. This is limited to unmanaged devices. The authentication policy must be
* provided to be able to make this request successfully.
*
+ * <p> This intent should be started using {@link Activity#startActivityForResult(Intent, int)}
+ * to verify whether the request was successful and whether the user accepted or denied the
+ * request. If the user successfully receives and accepts the request, the result code will be
+ * {@link Activity#RESULT_OK}, otherwise the result code will be
+ * {@link Activity#RESULT_CANCELED}.
+ *
+ * <p> {@link KeyChain#isCredentialManagementApp(Context)} should be used to determine whether
+ * an app is already the credential management app.
+ *
* @param policy The authentication policy determines which alias for a private key and
* certificate pair should be used for authentication.
*/
@@ -589,6 +600,55 @@ public final class KeyChain {
}
/**
+ * Check whether the caller is the credential management app {@link CredentialManagementApp}.
+ * The credential management app has the ability to manage the user's KeyChain credentials
+ * on unmanaged devices.
+ *
+ * <p> {@link KeyChain#createManageCredentialsIntent} should be used by an app to request to
+ * become the credential management app. The user must approve this request before the app can
+ * manage the user's credentials. There can only be one credential management on the device.
+ *
+ * @return {@code true} if the caller is the credential management app.
+ */
+ public static boolean isCredentialManagementApp(@NonNull Context context) {
+ boolean isCredentialManagementApp = false;
+ try (KeyChainConnection keyChainConnection = KeyChain.bind(context)) {
+ isCredentialManagementApp = keyChainConnection.getService()
+ .isCredentialManagementApp(context.getPackageName());
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted while checking whether the caller is the "
+ + "credential management app.", e);
+ } catch (SecurityException e) {
+ isCredentialManagementApp = false;
+ }
+ return isCredentialManagementApp;
+ }
+
+ /**
+ * Called by the credential management app to get the authentication policy
+ * {@link AppUriAuthenticationPolicy}.
+ *
+ * @return the credential management app's authentication policy.
+ * @throws SecurityException if the caller is not the credential management app.
+ */
+ @NonNull
+ public static AppUriAuthenticationPolicy getCredentialManagementAppPolicy(
+ @NonNull Context context) throws SecurityException {
+ AppUriAuthenticationPolicy policy = null;
+ try (KeyChainConnection keyChainConnection = KeyChain.bind(context)) {
+ policy = keyChainConnection.getService().getCredentialManagementAppPolicy();
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(
+ "Interrupted while getting credential management app policy.", e);
+ }
+ return policy;
+ }
+
+ /**
* Set a credential management app. The credential management app has the ability to manage
* the user's KeyChain credentials on unmanaged devices.
*
@@ -682,6 +742,33 @@ public final class KeyChain {
return null;
}
+ /**
+ * This prefix is used to disambiguate grant aliase strings from normal key alias strings.
+ * Technically, a key alias string can use the same prefix. However, a collision does not
+ * lead to privilege escalation, because grants are access controlled in the Keystore daemon.
+ * @hide
+ */
+ public static final String GRANT_ALIAS_PREFIX = "ks2_keychain_grant_id:";
+
+ private static KeyDescriptor getGrantDescriptor(String keyid) {
+ KeyDescriptor result = new KeyDescriptor();
+ result.domain = Domain.GRANT;
+ result.blob = null;
+ result.alias = null;
+ try {
+ result.nspace = Long.parseUnsignedLong(
+ keyid.substring(GRANT_ALIAS_PREFIX.length()), 16 /* radix */);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ return result;
+ }
+
+ /** @hide */
+ public static String getGrantString(KeyDescriptor key) {
+ return String.format(GRANT_ALIAS_PREFIX + "%016X", key.nspace);
+ }
+
/** @hide */
@Nullable @WorkerThread
public static KeyPair getKeyPair(@NonNull Context context, @NonNull String alias)
@@ -705,11 +792,23 @@ public final class KeyChain {
if (keyId == null) {
return null;
+ }
+
+ if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+ try {
+ return android.security.keystore2.AndroidKeyStoreProvider
+ .loadAndroidKeyStoreKeyPairFromKeystore(
+ KeyStore2.getInstance(),
+ getGrantDescriptor(keyId));
+ } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
+ throw new KeyChainException(e);
+ }
} else {
try {
return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
KeyStore.getInstance(), keyId, KeyStore.UID_SELF);
- } catch (RuntimeException | UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
+ } catch (RuntimeException | UnrecoverableKeyException
+ | KeyPermanentlyInvalidatedException e) {
throw new KeyChainException(e);
}
}
@@ -827,11 +926,8 @@ public final class KeyChain {
@Deprecated
public static boolean isBoundKeyAlgorithm(
@NonNull @KeyProperties.KeyAlgorithmEnum String algorithm) {
- if (!isKeyAlgorithmSupported(algorithm)) {
- return false;
- }
-
- return KeyStore.getInstance().isHardwareBacked(algorithm);
+ // All supported algorithms are hardware backed. Individual keys may not be.
+ return true;
}
/** @hide */
diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
index c20cf01a993e..a6e33664f2b1 100644
--- a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
@@ -59,7 +59,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeString(mSpec.getKeystoreAlias());
out.writeInt(mSpec.getPurposes());
- out.writeInt(mSpec.getUid());
+ out.writeInt(mSpec.getNamespace());
out.writeInt(mSpec.getKeySize());
// Only needs to support RSAKeyGenParameterSpec and ECGenParameterSpec.
@@ -125,7 +125,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable {
private ParcelableKeyGenParameterSpec(Parcel in) {
final String keystoreAlias = in.readString();
final int purposes = in.readInt();
- final int uid = in.readInt();
+ final int namespace = in.readInt();
final int keySize = in.readInt();
final int keySpecType = in.readInt();
@@ -177,7 +177,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable {
// KeyGenParameterSpec constructor (whereas using a builder would silently drop them).
mSpec = new KeyGenParameterSpec(
keystoreAlias,
- uid,
+ namespace,
keySize,
algorithmSpec,
certificateSubject,
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index b3bfd6a3a97a..e401add9ece7 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -154,7 +154,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
private KeyGenParameterSpec mSpec;
private String mEntryAlias;
- private int mEntryUid;
+ private int mEntryNamespace;
private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm;
private int mKeymasterAlgorithm = -1;
private int mKeySizeBits;
@@ -218,7 +218,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
}
mEntryAlias = spec.getKeystoreAlias();
- mEntryUid = spec.getUid();
+ mEntryNamespace = spec.getNamespace();
mSpec = spec;
mKeymasterAlgorithm = keymasterAlgorithm;
mKeySizeBits = spec.getKeySize();
@@ -439,7 +439,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
private void resetAll() {
mEntryAlias = null;
- mEntryUid = KeyProperties.NAMESPACE_APPLICATION;
+ mEntryNamespace = KeyProperties.NAMESPACE_APPLICATION;
mJcaKeyAlgorithm = null;
mKeymasterAlgorithm = -1;
mKeymasterPurposes = null;
@@ -541,10 +541,10 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
KeyDescriptor descriptor = new KeyDescriptor();
descriptor.alias = mEntryAlias;
- descriptor.domain = mEntryUid == KeyProperties.NAMESPACE_APPLICATION
+ descriptor.domain = mEntryNamespace == KeyProperties.NAMESPACE_APPLICATION
? Domain.APP
: Domain.SELINUX;
- descriptor.nspace = mEntryUid;
+ descriptor.nspace = mEntryNamespace;
descriptor.blob = null;
boolean success = false;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index e1011155248e..35059ac929c3 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -273,10 +273,10 @@ public class AndroidKeyStoreProvider extends Provider {
/** @hide **/
@NonNull
public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
- @NonNull KeyStore2 keyStore, @NonNull String privateKeyAlias, int namespace)
+ @NonNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor)
throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
AndroidKeyStoreKey key =
- loadAndroidKeyStoreKeyFromKeystore(keyStore, privateKeyAlias, namespace);
+ loadAndroidKeyStoreKeyFromKeystore(keyStore, descriptor);
if (key instanceof AndroidKeyStorePublicKey) {
AndroidKeyStorePublicKey publicKey = (AndroidKeyStorePublicKey) key;
return new KeyPair(publicKey, publicKey.getPrivateKey());
@@ -336,7 +336,7 @@ public class AndroidKeyStoreProvider extends Provider {
@NonNull
public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore(
@NonNull KeyStore2 keyStore, @NonNull String alias, int namespace)
- throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
+ throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
KeyDescriptor descriptor = new KeyDescriptor();
if (namespace == KeyProperties.NAMESPACE_APPLICATION) {
@@ -348,6 +348,18 @@ public class AndroidKeyStoreProvider extends Provider {
}
descriptor.alias = alias;
descriptor.blob = null;
+
+ final AndroidKeyStoreKey key = loadAndroidKeyStoreKeyFromKeystore(keyStore, descriptor);
+ if (key instanceof AndroidKeyStorePublicKey) {
+ return ((AndroidKeyStorePublicKey) key).getPrivateKey();
+ } else {
+ return key;
+ }
+ }
+
+ private static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore(
+ @NonNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor)
+ throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
KeyEntryResponse response = null;
try {
response = keyStore.getKeyEntry(descriptor);
@@ -397,7 +409,7 @@ public class AndroidKeyStoreProvider extends Provider {
keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) {
return makeAndroidKeyStorePublicKeyFromKeyEntryResponse(descriptor, response.metadata,
new KeyStoreSecurityLevel(response.iSecurityLevel),
- keymasterAlgorithm).getPrivateKey();
+ keymasterAlgorithm);
} else {
throw new UnrecoverableKeyException("Key algorithm unknown");
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java
index 59271e9fb63c..e6e6d4a1934f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java
@@ -22,7 +22,7 @@ import android.os.RemoteException;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.pip.PinnedStackListenerForwarder;
-import com.android.wm.shell.pip.PinnedStackListenerForwarder.PinnedStackListener;
+import com.android.wm.shell.pip.PinnedStackListenerForwarder.PinnedTaskListener;
/**
* The singleton wrapper to communicate between WindowManagerService and WMShell features
@@ -46,7 +46,7 @@ public class WindowManagerShellWrapper {
* Adds a pinned stack listener, which will receive updates from the window manager service
* along with any other pinned stack listeners that were added via this method.
*/
- public void addPinnedStackListener(PinnedStackListener listener)
+ public void addPinnedStackListener(PinnedTaskListener listener)
throws RemoteException {
mPinnedStackListenerForwarder.addListener(listener);
mPinnedStackListenerForwarder.register(DEFAULT_DISPLAY);
@@ -55,7 +55,7 @@ public class WindowManagerShellWrapper {
/**
* Removes a pinned stack listener.
*/
- public void removePinnedStackListener(PinnedStackListener listener) {
+ public void removePinnedStackListener(PinnedTaskListener listener) {
mPinnedStackListenerForwarder.removeListener(listener);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
index 79f9dcd8a1fb..562b32b41dd2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
@@ -34,6 +34,7 @@ import androidx.annotation.Nullable;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.split.SplitLayout;
@@ -57,12 +58,14 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.LayoutChan
private final AppPairsController mController;
private final SyncTransactionQueue mSyncQueue;
private final DisplayController mDisplayController;
+ private final DisplayImeController mDisplayImeController;
private SplitLayout mSplitLayout;
AppPair(AppPairsController controller) {
mController = controller;
mSyncQueue = controller.getSyncTransactionQueue();
mDisplayController = controller.getDisplayController();
+ mDisplayImeController = controller.getDisplayImeController();
}
int getRootTaskId() {
@@ -97,7 +100,7 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.LayoutChan
mSplitLayout = new SplitLayout(TAG + "SplitDivider",
mDisplayController.getDisplayContext(mRootTaskInfo.displayId),
mRootTaskInfo.configuration, this /* layoutChangeListener */,
- b -> b.setParent(mRootTaskLeash));
+ b -> b.setParent(mRootTaskLeash), mDisplayImeController);
final WindowContainerToken token1 = task1.token;
final WindowContainerToken token2 = task2.token;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
index 0415f12496f2..b159333e9a0e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
@@ -23,17 +23,16 @@ import android.util.Slog;
import android.util.SparseArray;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import java.io.PrintWriter;
-import java.util.concurrent.TimeUnit;
/**
* Class manages app-pairs multitasking mode and implements the main interface {@link AppPairs}.
@@ -50,12 +49,15 @@ public class AppPairsController {
// Active app-pairs mapped by root task id key.
private final SparseArray<AppPair> mActiveAppPairs = new SparseArray<>();
private final DisplayController mDisplayController;
+ private final DisplayImeController mDisplayImeController;
public AppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue,
- DisplayController displayController, ShellExecutor mainExecutor) {
+ DisplayController displayController, ShellExecutor mainExecutor,
+ DisplayImeController displayImeController) {
mTaskOrganizer = organizer;
mSyncQueue = syncQueue;
mDisplayController = displayController;
+ mDisplayImeController = displayImeController;
mMainExecutor = mainExecutor;
}
@@ -130,18 +132,22 @@ public class AppPairsController {
}
}
- public ShellTaskOrganizer getTaskOrganizer() {
+ ShellTaskOrganizer getTaskOrganizer() {
return mTaskOrganizer;
}
- public SyncTransactionQueue getSyncTransactionQueue() {
+ SyncTransactionQueue getSyncTransactionQueue() {
return mSyncQueue;
}
- public DisplayController getDisplayController() {
+ DisplayController getDisplayController() {
return mDisplayController;
}
+ DisplayImeController getDisplayImeController() {
+ return mDisplayImeController;
+ }
+
public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
final String childPrefix = innerPrefix + " ";
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 0ee1f0642352..8697be9db3fd 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
@@ -124,6 +124,7 @@ public class Bubble implements BubbleViewProvider {
private int mDesiredHeight;
@DimenRes
private int mDesiredHeightResId;
+ private int mTaskId;
/** for logging **/
@Nullable
@@ -162,7 +163,7 @@ public class Bubble implements BubbleViewProvider {
*/
Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo,
final int desiredHeight, final int desiredHeightResId, @Nullable final String title,
- Executor mainExecutor) {
+ int taskId, Executor mainExecutor) {
Objects.requireNonNull(key);
Objects.requireNonNull(shortcutInfo);
mMetadataShortcutId = shortcutInfo.getId();
@@ -178,6 +179,7 @@ public class Bubble implements BubbleViewProvider {
mTitle = title;
mShowBubbleUpdateDot = false;
mMainExecutor = mainExecutor;
+ mTaskId = taskId;
}
@VisibleForTesting(visibility = PRIVATE)
@@ -197,6 +199,7 @@ public class Bubble implements BubbleViewProvider {
});
};
mMainExecutor = mainExecutor;
+ mTaskId = INVALID_TASK_ID;
setEntry(entry);
}
@@ -520,7 +523,7 @@ public class Bubble implements BubbleViewProvider {
*/
@Override
public int getTaskId() {
- return mExpandedView != null ? mExpandedView.getTaskId() : INVALID_TASK_ID;
+ return mExpandedView != null ? mExpandedView.getTaskId() : mTaskId;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 047df5ba7ca9..1320780bfb8f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1213,7 +1213,7 @@ public class BubbleController {
/** PinnedStackListener that dispatches IME visibility updates to the stack. */
//TODO(b/170442945): Better way to do this / insets listener?
- private class BubblesImeListener extends PinnedStackListenerForwarder.PinnedStackListener {
+ private class BubblesImeListener extends PinnedStackListenerForwarder.PinnedTaskListener {
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
if (mStackView != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
index 3108b02cc010..241755227af0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
@@ -28,7 +28,6 @@ import com.android.wm.shell.bubbles.storage.BubbleEntity
import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
import com.android.wm.shell.bubbles.storage.BubbleVolatileRepository
import com.android.wm.shell.common.ShellExecutor
-import com.android.wm.shell.common.annotations.ExternalThread
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -36,8 +35,11 @@ import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
-internal class BubbleDataRepository(context: Context, private val launcherApps: LauncherApps,
- private val mainExecutor : ShellExecutor) {
+internal class BubbleDataRepository(
+ context: Context,
+ private val launcherApps: LauncherApps,
+ private val mainExecutor: ShellExecutor
+) {
private val volatileRepository = BubbleVolatileRepository(launcherApps)
private val persistentRepository = BubblePersistentRepository(context)
@@ -78,7 +80,8 @@ internal class BubbleDataRepository(context: Context, private val launcherApps:
b.key,
b.rawDesiredHeight,
b.rawDesiredHeightResId,
- b.title
+ b.title,
+ b.taskId
)
}
}
@@ -168,6 +171,7 @@ internal class BubbleDataRepository(context: Context, private val launcherApps:
entity.desiredHeight,
entity.desiredHeightResId,
entity.title,
+ entity.taskId,
mainExecutor
) }
}
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 a3edc20e242a..a8ab4064455c 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
@@ -1539,19 +1539,16 @@ public class BubbleStackView extends FrameLayout
* Update bubble order and pointer position.
*/
public void updateBubbleOrder(List<Bubble> bubbles) {
- if (isExpansionAnimating()) {
- return;
- }
final Runnable reorder = () -> {
for (int i = 0; i < bubbles.size(); i++) {
Bubble bubble = bubbles.get(i);
mBubbleContainer.reorderView(bubble.getIconView(), i);
}
};
- if (mIsExpanded) {
+ if (mIsExpanded || isExpansionAnimating()) {
reorder.run();
updateBadgesAndZOrder(false /* setBadgeForCollapsedStack */);
- } else {
+ } else if (!isExpansionAnimating()) {
List<View> bubbleViews = bubbles.stream()
.map(b -> b.getIconView()).collect(Collectors.toList());
mStackAnimationController.animateReorder(bubbleViews, reorder);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt
index aeba302bf487..d5cab5af42e4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt
@@ -25,5 +25,6 @@ data class BubbleEntity(
val key: String,
val desiredHeight: Int,
@DimenRes val desiredHeightResId: Int,
- val title: String? = null
+ val title: String? = null,
+ val taskId: Int
)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
index fe72bd301e04..470011b136fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
@@ -15,6 +15,7 @@
*/
package com.android.wm.shell.bubbles.storage
+import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.util.Xml
import com.android.internal.util.FastXmlSerializer
import com.android.internal.util.XmlUtils
@@ -38,6 +39,7 @@ private const val ATTR_KEY = "key"
private const val ATTR_DESIRED_HEIGHT = "h"
private const val ATTR_DESIRED_HEIGHT_RES_ID = "hid"
private const val ATTR_TITLE = "t"
+private const val ATTR_TASK_ID = "tid"
/**
* Writes the bubbles in xml format into given output stream.
@@ -70,6 +72,7 @@ private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleEntity) {
serializer.attribute(null, ATTR_DESIRED_HEIGHT, bubble.desiredHeight.toString())
serializer.attribute(null, ATTR_DESIRED_HEIGHT_RES_ID, bubble.desiredHeightResId.toString())
bubble.title?.let { serializer.attribute(null, ATTR_TITLE, it) }
+ serializer.attribute(null, ATTR_TASK_ID, bubble.taskId.toString())
serializer.endTag(null, TAG_BUBBLE)
} catch (e: IOException) {
throw RuntimeException(e)
@@ -103,7 +106,8 @@ private fun readXmlEntry(parser: XmlPullParser): BubbleEntity? {
parser.getAttributeWithName(ATTR_KEY) ?: return null,
parser.getAttributeWithName(ATTR_DESIRED_HEIGHT)?.toInt() ?: return null,
parser.getAttributeWithName(ATTR_DESIRED_HEIGHT_RES_ID)?.toInt() ?: return null,
- parser.getAttributeWithName(ATTR_TITLE)
+ parser.getAttributeWithName(ATTR_TITLE),
+ parser.getAttributeWithName(ATTR_TASK_ID)?.toInt() ?: INVALID_TASK_ID
)
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index 58a4baf39614..4564af438f32 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -22,6 +22,8 @@ import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.os.Process.SYSTEM_UID;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
+import static android.util.RotationUtils.rotateBounds;
+import static android.util.RotationUtils.rotateInsets;
import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_270;
@@ -37,7 +39,6 @@ import android.graphics.Rect;
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.DisplayMetrics;
-import android.util.RotationUtils;
import android.util.Size;
import android.view.Display;
import android.view.DisplayCutout;
@@ -241,38 +242,6 @@ public class DisplayLayout {
}
/**
- * Rotates bounds as if parentBounds and bounds are a group. The group is rotated by `delta`
- * 90-degree counter-clockwise increments. This assumes that parentBounds is at 0,0 and
- * remains at 0,0 after rotation.
- *
- * Only 'bounds' is mutated.
- */
- public static void rotateBounds(Rect inOutBounds, Rect parentBounds, int delta) {
- int rdelta = ((delta % 4) + 4) % 4;
- int origLeft = inOutBounds.left;
- switch (rdelta) {
- case 0:
- return;
- case 1:
- inOutBounds.left = inOutBounds.top;
- inOutBounds.top = parentBounds.right - inOutBounds.right;
- inOutBounds.right = inOutBounds.bottom;
- inOutBounds.bottom = parentBounds.right - origLeft;
- return;
- case 2:
- inOutBounds.left = parentBounds.right - inOutBounds.right;
- inOutBounds.right = parentBounds.right - origLeft;
- return;
- case 3:
- inOutBounds.left = parentBounds.bottom - inOutBounds.bottom;
- inOutBounds.bottom = inOutBounds.right;
- inOutBounds.right = parentBounds.bottom - inOutBounds.top;
- inOutBounds.top = origLeft;
- return;
- }
- }
-
- /**
* Calculates the stable insets if we already have the non-decor insets.
*/
private static void convertNonDecorInsetsToStableInsets(Resources res, Rect inOutInsets,
@@ -359,8 +328,7 @@ public class DisplayLayout {
if (rotation == ROTATION_0) {
return computeSafeInsets(cutout, displayWidth, displayHeight);
}
- final Insets waterfallInsets =
- RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
+ final Insets waterfallInsets = rotateInsets(cutout.getWaterfallInsets(), rotation);
final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
Rect[] cutoutRects = cutout.getBoundingRectsAll();
final Rect[] newBounds = new Rect[cutoutRects.length];
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
index e94080aa8db7..3b670057cb1a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
@@ -227,7 +227,7 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler.
}
@Override
- public void onActivityDismissingDockedStack() {
+ public void onActivityDismissingDockedTask() {
mMainHandler.sendEmptyMessage(ON_ACTIVITY_DISMISSING_DOCKED_STACK);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index c27c92961c2b..b9fdaa1ab1af 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -36,11 +36,13 @@ import androidx.annotation.Nullable;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.common.DisplayImeController;
/**
- * Stack divider for app pair.
+ * Divider for multi window splits.
*/
-public class DividerView extends FrameLayout implements View.OnTouchListener {
+public class DividerView extends FrameLayout implements View.OnTouchListener,
+ DisplayImeController.ImePositionProcessor {
public static final long TOUCH_ANIMATION_DURATION = 150;
public static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
@@ -56,6 +58,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
private boolean mMoving;
private int mStartPos;
private GestureDetector mDoubleTapDetector;
+ private boolean mInteractive;
public DividerView(@NonNull Context context) {
super(context);
@@ -91,12 +94,19 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
mTouchElevation = getResources().getDimensionPixelSize(
R.dimen.docked_stack_divider_lift_elevation);
mDoubleTapDetector = new GestureDetector(getContext(), new DoubleTapListener());
+ mInteractive = true;
setOnTouchListener(this);
}
@Override
+ public void onImeVisibilityChanged(int displayId, boolean isShowing) {
+ if (displayId != getDisplay().getDisplayId()) return;
+ setInteractive(!isShowing);
+ }
+
+ @Override
public boolean onTouch(View v, MotionEvent event) {
- if (mSplitLayout == null) {
+ if (mSplitLayout == null || !mInteractive) {
return false;
}
@@ -202,6 +212,13 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
mViewHost.relayout(lp);
}
+ private void setInteractive(boolean interactive) {
+ if (interactive == mInteractive) return;
+ mInteractive = interactive;
+ releaseTouching();
+ mHandle.setVisibility(mInteractive ? View.VISIBLE : View.INVISIBLE);
+ }
+
private boolean isLandscape() {
return getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 60231df37370..bacff78e6a67 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -35,6 +35,7 @@ import androidx.annotation.Nullable;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.common.DisplayImeController;
/**
* Records and handles layout of splits. Helps to calculate proper bounds when configuration or
@@ -59,11 +60,13 @@ public class SplitLayout {
public SplitLayout(String windowName, Context context, Configuration configuration,
LayoutChangeListener layoutChangeListener,
- SplitWindowManager.ParentContainerCallbacks parentContainerCallbacks) {
+ SplitWindowManager.ParentContainerCallbacks parentContainerCallbacks,
+ DisplayImeController displayImeController) {
mContext = context.createConfigurationContext(configuration);
mLayoutChangeListener = layoutChangeListener;
mSplitWindowManager = new SplitWindowManager(
- windowName, mContext, configuration, parentContainerCallbacks);
+ windowName, mContext, configuration, parentContainerCallbacks,
+ displayImeController);
mDividerWindowWidth = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_thickness);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index 87f0c25c93df..f6efb0120dda 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -46,6 +46,7 @@ import android.view.WindowlessWindowManager;
import androidx.annotation.Nullable;
import com.android.wm.shell.R;
+import com.android.wm.shell.common.DisplayImeController;
/**
* Holds view hierarchy of a root surface and helps to inflate {@link DividerView} for a split.
@@ -53,23 +54,27 @@ import com.android.wm.shell.R;
public final class SplitWindowManager extends WindowlessWindowManager {
private static final String TAG = SplitWindowManager.class.getSimpleName();
+ private final String mWindowName;
+ private final DisplayImeController mDisplayImeController;
private final ParentContainerCallbacks mParentContainerCallbacks;
private Context mContext;
private SurfaceControlViewHost mViewHost;
private SurfaceControl mLeash;
private boolean mResizingSplits;
- private final String mWindowName;
+ private DividerView mDividerView;
public interface ParentContainerCallbacks {
void attachToParentSurface(SurfaceControl.Builder b);
}
public SplitWindowManager(String windowName, Context context, Configuration config,
- ParentContainerCallbacks parentContainerCallbacks) {
+ ParentContainerCallbacks parentContainerCallbacks,
+ DisplayImeController displayImeController) {
super(config, null /* rootSurface */, null /* hostInputToken */);
mContext = context.createConfigurationContext(config);
mParentContainerCallbacks = parentContainerCallbacks;
mWindowName = windowName;
+ mDisplayImeController = displayImeController;
}
@Override
@@ -103,14 +108,16 @@ public final class SplitWindowManager extends WindowlessWindowManager {
/** Inflates {@link DividerView} on to the root surface. */
void init(SplitLayout splitLayout) {
- if (mViewHost == null) {
- mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+ if (mDividerView != null || mViewHost != null) {
+ throw new UnsupportedOperationException(
+ "Try to inflate divider view again without release first");
}
- final Rect dividerBounds = splitLayout.getDividerBounds();
- final DividerView dividerView = (DividerView) LayoutInflater.from(mContext)
+ mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+ mDividerView = (DividerView) LayoutInflater.from(mContext)
.inflate(R.layout.split_divider, null /* root */);
+ final Rect dividerBounds = splitLayout.getDividerBounds();
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
dividerBounds.width(), dividerBounds.height(), TYPE_DOCK_DIVIDER,
FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL | FLAG_WATCH_OUTSIDE_TOUCH
@@ -119,8 +126,9 @@ public final class SplitWindowManager extends WindowlessWindowManager {
lp.token = new Binder();
lp.setTitle(mWindowName);
lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
- mViewHost.setView(dividerView, lp);
- dividerView.setup(splitLayout, mViewHost);
+ mViewHost.setView(mDividerView, lp);
+ mDividerView.setup(splitLayout, mViewHost);
+ mDisplayImeController.addPositionProcessor(mDividerView);
}
/**
@@ -128,6 +136,11 @@ public final class SplitWindowManager extends WindowlessWindowManager {
* hierarchy.
*/
void release() {
+ if (mDividerView != null) {
+ mDisplayImeController.removePositionProcessor(mDividerView);
+ mDividerView = null;
+ }
+
if (mViewHost != null){
mViewHost.release();
mViewHost = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java
index 477ec339f1db..40244fbb4503 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.legacysplitscreen;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.util.RotationUtils.rotateBounds;
import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_LEFT;
@@ -244,7 +245,7 @@ public class LegacySplitDisplayLayout {
DividerSnapAlgorithm snap = initSnapAlgorithmForRotation(context, tmpDL, dividerSize);
tmpRect.set(bounds);
- DisplayLayout.rotateBounds(tmpRect, displayRect, rotation - dl.rotation());
+ rotateBounds(tmpRect, displayRect, dl.rotation(), rotation);
rotatedDisplayRect.set(0, 0, tmpDL.width(), tmpDL.height());
final int dockSide = getPrimarySplitSide(tmpRect, rotatedDisplayRect,
tmpDL.getOrientation());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
index c8f89876222e..82468ad999b4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
@@ -105,7 +105,7 @@ class WindowManagerProxy {
synchronized (mDockedRect) {
mTouchableRegion.set(region);
}
- WindowManagerGlobal.getWindowManagerService().setDockedStackDividerTouchRegion(
+ WindowManagerGlobal.getWindowManagerService().setDockedTaskDividerTouchRegion(
mTouchableRegion);
} catch (RemoteException e) {
Log.w(TAG, "Failed to set touchable region: " + e);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index afc8a097dd05..4c5cc226b40f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -202,6 +202,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
animateWindows(token, leash, fromBounds, toBounds, direction,
mEnterExitAnimationDurationMs);
wct.setBounds(token, toBounds);
+ wct.setAppBounds(token, toBounds);
});
applyTransaction(wct);
}
@@ -231,6 +232,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
// DisplayRotationController will applyTransaction() after finish rotating
if (wct != null) {
wct.setBounds(token, null/* reset */);
+ wct.setAppBounds(token, null/* reset */);
}
});
tx.apply();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
index 8f8ec475a85c..b3b1ba7cd1c1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
@@ -20,7 +20,7 @@ import android.app.RemoteAction;
import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
import android.os.RemoteException;
-import android.view.IPinnedStackListener;
+import android.view.IPinnedTaskListener;
import android.view.WindowManagerGlobal;
import androidx.annotation.BinderThread;
@@ -32,66 +32,66 @@ import java.util.ArrayList;
/**
* PinnedStackListener that simply forwards all calls to each listener added via
* {@link #addListener}. This is necessary since calling
- * {@link com.android.server.wm.WindowManagerService#registerPinnedStackListener} replaces any
+ * {@link com.android.server.wm.WindowManagerService#registerPinnedTaskListener} replaces any
* previously set listener.
*/
public class PinnedStackListenerForwarder {
- private final IPinnedStackListener mListenerImpl = new PinnedStackListenerImpl();
+ private final IPinnedTaskListener mListenerImpl = new PinnedTaskListenerImpl();
private final ShellExecutor mMainExecutor;
- private final ArrayList<PinnedStackListener> mListeners = new ArrayList<>();
+ private final ArrayList<PinnedTaskListener> mListeners = new ArrayList<>();
public PinnedStackListenerForwarder(ShellExecutor mainExecutor) {
mMainExecutor = mainExecutor;
}
/** Adds a listener to receive updates from the WindowManagerService. */
- public void addListener(PinnedStackListener listener) {
+ public void addListener(PinnedTaskListener listener) {
mListeners.add(listener);
}
/** Removes a listener so it will no longer receive updates from the WindowManagerService. */
- public void removeListener(PinnedStackListener listener) {
+ public void removeListener(PinnedTaskListener listener) {
mListeners.remove(listener);
}
public void register(int displayId) throws RemoteException {
- WindowManagerGlobal.getWindowManagerService().registerPinnedStackListener(
+ WindowManagerGlobal.getWindowManagerService().registerPinnedTaskListener(
displayId, mListenerImpl);
}
private void onMovementBoundsChanged(boolean fromImeAdjustment) {
- for (PinnedStackListener listener : mListeners) {
+ for (PinnedTaskListener listener : mListeners) {
listener.onMovementBoundsChanged(fromImeAdjustment);
}
}
private void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
- for (PinnedStackListener listener : mListeners) {
+ for (PinnedTaskListener listener : mListeners) {
listener.onImeVisibilityChanged(imeVisible, imeHeight);
}
}
private void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
- for (PinnedStackListener listener : mListeners) {
+ for (PinnedTaskListener listener : mListeners) {
listener.onActionsChanged(actions);
}
}
private void onActivityHidden(ComponentName componentName) {
- for (PinnedStackListener listener : mListeners) {
+ for (PinnedTaskListener listener : mListeners) {
listener.onActivityHidden(componentName);
}
}
private void onAspectRatioChanged(float aspectRatio) {
- for (PinnedStackListener listener : mListeners) {
+ for (PinnedTaskListener listener : mListeners) {
listener.onAspectRatioChanged(aspectRatio);
}
}
@BinderThread
- private class PinnedStackListenerImpl extends IPinnedStackListener.Stub {
+ private class PinnedTaskListenerImpl extends IPinnedTaskListener.Stub {
@Override
public void onMovementBoundsChanged(boolean fromImeAdjustment) {
mMainExecutor.execute(() -> {
@@ -129,10 +129,10 @@ public class PinnedStackListenerForwarder {
}
/**
- * A counterpart of {@link IPinnedStackListener} with empty implementations.
+ * A counterpart of {@link IPinnedTaskListener} with empty implementations.
* Subclasses can ignore those methods they do not intend to take action upon.
*/
- public static class PinnedStackListener {
+ public static class PinnedTaskListener {
public void onMovementBoundsChanged(boolean fromImeAdjustment) {}
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 5ffa9885a143..66560d339c5a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.pip;
+import static android.util.RotationUtils.rotateBounds;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
@@ -33,7 +34,6 @@ import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.wm.shell.animation.Interpolators;
-import com.android.wm.shell.common.DisplayLayout;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -448,7 +448,7 @@ public class PipAnimationController {
// Rotate the end bounds according to the rotation delta because the display will
// be rotated to the same orientation.
rotatedEndRect = new Rect(endValue);
- DisplayLayout.rotateBounds(rotatedEndRect, endValue, rotationDelta);
+ rotateBounds(rotatedEndRect, endValue, rotationDelta);
} else {
rotatedEndRect = null;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
index 1a4616c5f591..6afcc06aa1ae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
@@ -32,6 +32,7 @@ import android.media.session.MediaController;
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;
@@ -76,6 +77,7 @@ public class PipMediaController {
private final Context mContext;
private final Handler mMainHandler;
+ private final HandlerExecutor mHandlerExecutor;
private final MediaSessionManager mMediaSessionManager;
private MediaController mMediaController;
@@ -123,6 +125,7 @@ public class PipMediaController {
public PipMediaController(Context context, Handler mainHandler) {
mContext = context;
mMainHandler = mainHandler;
+ mHandlerExecutor = new HandlerExecutor(mMainHandler);
IntentFilter mediaControlFilter = new IntentFilter();
mediaControlFilter.addAction(ACTION_PLAY);
mediaControlFilter.addAction(ACTION_PAUSE);
@@ -247,8 +250,8 @@ public class PipMediaController {
*/
public void registerSessionListenerForCurrentUser() {
mMediaSessionManager.removeOnActiveSessionsChangedListener(mSessionsChangedListener);
- mMediaSessionManager.addOnActiveSessionsChangedListener(mSessionsChangedListener, null,
- UserHandle.CURRENT, mMainHandler);
+ mMediaSessionManager.addOnActiveSessionsChangedListener(null, UserHandle.CURRENT,
+ mHandlerExecutor, mSessionsChangedListener);
}
/**
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 4a2a032d8d1c..7fff37d082b1 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
@@ -93,8 +93,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb
protected PhonePipMenuController mMenuController;
protected PipTaskOrganizer mPipTaskOrganizer;
- protected PinnedStackListenerForwarder.PinnedStackListener mPinnedStackListener =
- new PipControllerPinnedStackListener();
+ protected PinnedStackListenerForwarder.PinnedTaskListener mPinnedTaskListener =
+ new PipControllerPinnedTaskListener();
/**
* Handler for display rotation changes.
@@ -178,8 +178,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb
/**
* Handler for messages from the PIP controller.
*/
- private class PipControllerPinnedStackListener extends
- PinnedStackListenerForwarder.PinnedStackListener {
+ private class PipControllerPinnedTaskListener extends
+ PinnedStackListenerForwarder.PinnedTaskListener {
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
mPipBoundsState.setImeVisibility(imeVisible, imeHeight);
@@ -310,7 +310,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
mPipBoundsState.setDisplayLayout(new DisplayLayout(context, context.getDisplay()));
try {
- mWindowManagerShellWrapper.addPinnedStackListener(mPinnedStackListener);
+ mWindowManagerShellWrapper.addPinnedStackListener(mPinnedTaskListener);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to register pinned stack listener", e);
}
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 56f183fd7303..70980191f103 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
@@ -377,7 +377,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
private void registerWmShellPinnedStackListener(WindowManagerShellWrapper wmShell) {
try {
- wmShell.addPinnedStackListener(new PinnedStackListenerForwarder.PinnedStackListener() {
+ wmShell.addPinnedStackListener(new PinnedStackListenerForwarder.PinnedTaskListener() {
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
if (DEBUG) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index b0167afa2e4e..11548adaf5d1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -42,6 +42,7 @@ import androidx.annotation.Nullable;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
@@ -62,18 +63,20 @@ public class SplitScreenController implements DragAndDropPolicy.Starter {
private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
private final ShellExecutor mMainExecutor;
private final SplitScreenImpl mImpl = new SplitScreenImpl();
+ private final DisplayImeController mDisplayImeController;
private StageCoordinator mStageCoordinator;
public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTDAOrganizer,
- ShellExecutor mainExecutor) {
+ ShellExecutor mainExecutor, DisplayImeController displayImeController) {
mTaskOrganizer = shellTaskOrganizer;
mSyncQueue = syncQueue;
mContext = context;
mRootTDAOrganizer = rootTDAOrganizer;
mMainExecutor = mainExecutor;
+ mDisplayImeController = displayImeController;
}
public SplitScreen asSplitScreen() {
@@ -84,7 +87,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter {
if (mStageCoordinator == null) {
// TODO: Multi-display
mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
- mRootTDAOrganizer, mTaskOrganizer);
+ mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index e44c820a656a..22c97515ad76 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -39,6 +39,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.split.SplitLayout;
@@ -79,10 +80,12 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener,
private DisplayAreaInfo mDisplayAreaInfo;
private final Context mContext;
private final List<SplitScreen.SplitScreenListener> mListeners = new ArrayList<>();
+ private final DisplayImeController mDisplayImeController;
private boolean mExitSplitScreenOnHide = true;
StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
- RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer) {
+ RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
+ DisplayImeController displayImeController) {
mContext = context;
mDisplayId = displayId;
mSyncQueue = syncQueue;
@@ -90,13 +93,14 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener,
mTaskOrganizer = taskOrganizer;
mMainStage = new MainStage(mTaskOrganizer, mDisplayId, mMainStageListener, mSyncQueue);
mSideStage = new SideStage(mTaskOrganizer, mDisplayId, mSideStageListener, mSyncQueue);
+ mDisplayImeController = displayImeController;
mRootTDAOrganizer.registerListener(displayId, this);
}
@VisibleForTesting
StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
- MainStage mainStage, SideStage sideStage) {
+ MainStage mainStage, SideStage sideStage, DisplayImeController displayImeController) {
mContext = context;
mDisplayId = displayId;
mSyncQueue = syncQueue;
@@ -104,6 +108,7 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener,
mTaskOrganizer = taskOrganizer;
mMainStage = mainStage;
mSideStage = sideStage;
+ mDisplayImeController = displayImeController;
mRootTDAOrganizer.registerListener(displayId, this);
}
@@ -420,7 +425,8 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener,
if (mSplitLayout == null) {
mSplitLayout = new SplitLayout(TAG + "SplitDivider", mContext,
mDisplayAreaInfo.configuration, this,
- b -> mRootTDAOrganizer.attachToDisplayArea(mDisplayId, b));
+ b -> mRootTDAOrganizer.attachToDisplayArea(mDisplayId, b),
+ mDisplayImeController);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 45d551528940..76497706ce4f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -43,6 +43,7 @@ import java.util.List;
/**
* Util class to create the view for a splash screen content.
+ *
* @hide
*/
public class SplashscreenContentDrawer {
@@ -349,7 +350,7 @@ public class SplashscreenContentDrawer {
// Calculate the difference between two colors based on the HSV dimensions.
final float normalizeH = minAngle / 180f;
- final double square = Math.pow(normalizeH, 2)
+ final double square = Math.pow(normalizeH, 2)
+ Math.pow(aHsv[1] - bHsv[1], 2)
+ Math.pow(aHsv[2] - bHsv[2], 2);
final double mean = square / 3;
@@ -433,8 +434,11 @@ public class SplashscreenContentDrawer {
*/
private interface ColorTester {
float nonTransparentRatio();
+
boolean isComplexColor();
+
int getDominantColor();
+
boolean isGrayscale();
}
@@ -511,14 +515,17 @@ public class SplashscreenContentDrawer {
// restore to original bounds
drawable.setBounds(initialBounds);
- final Palette.Builder builder = new Palette.Builder(bitmap)
- .maximumColorCount(5).clearFilters();
+ final Palette.Builder builder;
// The Palette API will ignore Alpha, so it cannot handle transparent pixels, but
// sometimes we will need this information to know if this Drawable object is
// transparent.
mFilterTransparent = filterTransparent;
if (mFilterTransparent) {
- builder.setQuantizer(TRANSPARENT_FILTER_QUANTIZER);
+ builder = new Palette.Builder(bitmap, TRANSPARENT_FILTER_QUANTIZER)
+ .maximumColorCount(5);
+ } else {
+ builder = new Palette.Builder(bitmap, null)
+ .maximumColorCount(5);
}
mPalette = builder.generate();
bitmap.recycle();
@@ -538,7 +545,7 @@ public class SplashscreenContentDrawer {
public int getDominantColor() {
final Palette.Swatch mainSwatch = mPalette.getDominantSwatch();
if (mainSwatch != null) {
- return mainSwatch.getRgb();
+ return mainSwatch.getInt();
}
return Color.BLACK;
}
@@ -549,7 +556,7 @@ public class SplashscreenContentDrawer {
if (swatches != null) {
for (int i = swatches.size() - 1; i >= 0; i--) {
Palette.Swatch swatch = swatches.get(i);
- if (!isGrayscaleColor(swatch.getRgb())) {
+ if (!isGrayscaleColor(swatch.getInt())) {
return false;
}
}
@@ -561,9 +568,9 @@ public class SplashscreenContentDrawer {
private static final int NON_TRANSPARENT = 0xFF000000;
private final Quantizer mInnerQuantizer = new VariationalKMeansQuantizer();
private float mNonTransparentRatio;
+
@Override
- public void quantize(final int[] pixels, final int maxColors,
- final Palette.Filter[] filters) {
+ public void quantize(final int[] pixels, final int maxColors) {
mNonTransparentRatio = 0;
int realSize = 0;
for (int i = pixels.length - 1; i > 0; i--) {
@@ -575,7 +582,7 @@ public class SplashscreenContentDrawer {
if (DEBUG) {
Slog.d(TAG, "quantize: this is pure transparent image");
}
- mInnerQuantizer.quantize(pixels, maxColors, filters);
+ mInnerQuantizer.quantize(pixels, maxColors);
return;
}
mNonTransparentRatio = (float) realSize / pixels.length;
@@ -587,7 +594,7 @@ public class SplashscreenContentDrawer {
rowIndex++;
}
}
- mInnerQuantizer.quantize(samplePixels, maxColors, filters);
+ mInnerQuantizer.quantize(samplePixels, maxColors);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 59f8c1df1213..2182ee5590e1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -16,55 +16,78 @@
package com.android.wm.shell.transition;
+import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
+import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Rect;
import android.os.IBinder;
import android.util.ArrayMap;
+import android.view.Choreographer;
import android.view.SurfaceControl;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
+import com.android.internal.R;
+import com.android.internal.policy.AttributeCache;
+import com.android.internal.policy.TransitionAnimation;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.util.ArrayList;
/** The default handler that handles anything not already handled. */
public class DefaultTransitionHandler implements Transitions.TransitionHandler {
+ private static final int MAX_ANIMATION_DURATION = 3000;
+
private final TransactionPool mTransactionPool;
private final ShellExecutor mMainExecutor;
private final ShellExecutor mAnimExecutor;
+ private final TransitionAnimation mTransitionAnimation;
/** Keeps track of the currently-running animations associated with each transition. */
private final ArrayMap<IBinder, ArrayList<Animator>> mAnimations = new ArrayMap<>();
- DefaultTransitionHandler(@NonNull TransactionPool transactionPool,
+ private float mTransitionAnimationScaleSetting = 1.0f;
+
+ DefaultTransitionHandler(@NonNull TransactionPool transactionPool, Context context,
@NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
mTransactionPool = transactionPool;
mMainExecutor = mainExecutor;
mAnimExecutor = animExecutor;
+ mTransitionAnimation = new TransitionAnimation(context, false /* debug */, Transitions.TAG);
+
+ AttributeCache.init(context);
}
@Override
public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ "start default transition animation, info = %s", info);
if (mAnimations.containsKey(transition)) {
throw new IllegalStateException("Got a duplicate startAnimation call for "
+ transition);
}
final ArrayList<Animator> animations = new ArrayList<>();
mAnimations.put(transition, animations);
- final boolean isOpening = Transitions.isOpeningType(info.getType());
final Runnable onAnimFinish = () -> {
if (!animations.isEmpty()) return;
@@ -77,19 +100,9 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
// Don't animate anything with an animating parent
if (change.getParent() != null) continue;
- final int mode = change.getMode();
- if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
- if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
- // This received a transferred starting window, so don't animate
- continue;
- }
- // fade in
- startExampleAnimation(
- animations, change.getLeash(), true /* show */, onAnimFinish);
- } else if (!isOpening && (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK)) {
- // fade out
- startExampleAnimation(
- animations, change.getLeash(), false /* show */, onAnimFinish);
+ Animation a = loadAnimation(info.getType(), change);
+ if (a != null) {
+ startAnimInternal(animations, a, change.getLeash(), onAnimFinish);
}
}
t.apply();
@@ -105,32 +118,93 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
return null;
}
- // TODO(shell-transitions): real animations
- private void startExampleAnimation(@NonNull ArrayList<Animator> animations,
- @NonNull SurfaceControl leash, boolean show, @NonNull Runnable finishCallback) {
- final float end = show ? 1.f : 0.f;
- final float start = 1.f - end;
+ @Override
+ public void setAnimScaleSetting(float scale) {
+ mTransitionAnimationScaleSetting = scale;
+ }
+
+ @Nullable
+ private Animation loadAnimation(int type, TransitionInfo.Change change) {
+ // TODO(b/178678389): It should handle more type animation here
+ Animation a = null;
+
+ final boolean isOpening = Transitions.isOpeningType(type);
+ final int mode = change.getMode();
+ final int flags = change.getFlags();
+
+ if (mode == TRANSIT_OPEN && isOpening) {
+ if ((flags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
+ // This received a transferred starting window, so don't animate
+ return null;
+ }
+
+ if (change.getTaskInfo() != null) {
+ a = mTransitionAnimation.loadDefaultAnimationAttr(
+ R.styleable.WindowAnimation_taskOpenEnterAnimation);
+ } else {
+ a = mTransitionAnimation.loadDefaultAnimationRes((flags & FLAG_TRANSLUCENT) == 0
+ ? R.anim.activity_open_enter : R.anim.activity_translucent_open_enter);
+ }
+ } else if (mode == TRANSIT_TO_FRONT && isOpening) {
+ if ((flags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
+ // This received a transferred starting window, so don't animate
+ return null;
+ }
+
+ a = mTransitionAnimation.loadDefaultAnimationAttr(
+ R.styleable.WindowAnimation_taskToFrontEnterAnimation);
+ } else if (mode == TRANSIT_CLOSE && !isOpening) {
+ if (change.getTaskInfo() != null) {
+ a = mTransitionAnimation.loadDefaultAnimationAttr(
+ R.styleable.WindowAnimation_taskCloseExitAnimation);
+ } else {
+ a = mTransitionAnimation.loadDefaultAnimationRes((flags & FLAG_TRANSLUCENT) == 0
+ ? R.anim.activity_close_exit : R.anim.activity_translucent_close_exit);
+ }
+ } else if (mode == TRANSIT_TO_BACK && !isOpening) {
+ a = mTransitionAnimation.loadDefaultAnimationAttr(
+ R.styleable.WindowAnimation_taskToBackExitAnimation);
+ } else if (mode == TRANSIT_CHANGE) {
+ // In the absence of a specific adapter, we just want to keep everything stationary.
+ a = new AlphaAnimation(1.f, 1.f);
+ a.setDuration(TransitionAnimation.DEFAULT_APP_TRANSITION_DURATION);
+ }
+
+ if (a != null) {
+ Rect start = change.getStartAbsBounds();
+ Rect end = change.getEndAbsBounds();
+ a.restrictDuration(MAX_ANIMATION_DURATION);
+ a.initialize(end.width(), end.height(), start.width(), start.height());
+ a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
+ }
+ return a;
+ }
+
+ private void startAnimInternal(@NonNull ArrayList<Animator> animations, @NonNull Animation anim,
+ @NonNull SurfaceControl leash, @NonNull Runnable finishCallback) {
final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
- final ValueAnimator va = ValueAnimator.ofFloat(start, end);
- va.setDuration(500);
+ final ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
+ final Transformation transformation = new Transformation();
+ final float[] matrix = new float[9];
+ // Animation length is already expected to be scaled.
+ va.overrideDurationScale(1.0f);
+ va.setDuration(anim.computeDurationHint());
va.addUpdateListener(animation -> {
- float fraction = animation.getAnimatedFraction();
- transaction.setAlpha(leash, start * (1.f - fraction) + end * fraction);
- transaction.apply();
+ final long currentPlayTime = Math.min(va.getDuration(), va.getCurrentPlayTime());
+
+ applyTransformation(currentPlayTime, transaction, leash, anim, transformation, matrix);
});
+
final Runnable finisher = () -> {
- transaction.setAlpha(leash, end);
- transaction.apply();
+ applyTransformation(va.getDuration(), transaction, leash, anim, transformation, matrix);
+
mTransactionPool.release(transaction);
mMainExecutor.execute(() -> {
animations.remove(va);
finishCallback.run();
});
};
- va.addListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) { }
-
+ va.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
finisher.run();
@@ -140,11 +214,17 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
public void onAnimationCancel(Animator animation) {
finisher.run();
}
-
- @Override
- public void onAnimationRepeat(Animator animation) { }
});
animations.add(va);
mAnimExecutor.execute(va::start);
}
+
+ private static void applyTransformation(long time, SurfaceControl.Transaction t,
+ SurfaceControl leash, Animation anim, Transformation transformation, float[] matrix) {
+ anim.getTransformation(time, transformation);
+ t.setMatrix(leash, transformation.getMatrix(), matrix);
+ t.setAlpha(leash, transformation.getAlpha());
+ t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
+ t.apply();
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 10344892e766..89eee67bf5af 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -25,9 +25,13 @@ import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPI
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemProperties;
+import android.provider.Settings;
import android.util.ArrayMap;
import android.util.Log;
import android.view.SurfaceControl;
@@ -43,6 +47,7 @@ import android.window.WindowOrganizer;
import androidx.annotation.BinderThread;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -63,6 +68,7 @@ public class Transitions {
SystemProperties.getBoolean("persist.debug.shell_transit", false);
private final WindowOrganizer mOrganizer;
+ private final Context mContext;
private final ShellExecutor mMainExecutor;
private final ShellExecutor mAnimExecutor;
private final TransitionPlayerImpl mPlayerImpl;
@@ -72,6 +78,8 @@ public class Transitions {
/** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
+ private float mTransitionAnimationScaleSetting = 1.0f;
+
private static final class ActiveTransition {
TransitionHandler mFirstHandler = null;
}
@@ -84,26 +92,46 @@ public class Transitions {
}
public Transitions(@NonNull WindowOrganizer organizer, @NonNull TransactionPool pool,
- @NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
+ @NonNull Context context, @NonNull ShellExecutor mainExecutor,
+ @NonNull ShellExecutor animExecutor) {
mOrganizer = organizer;
+ mContext = context;
mMainExecutor = mainExecutor;
mAnimExecutor = animExecutor;
mPlayerImpl = new TransitionPlayerImpl();
// The very last handler (0 in the list) should be the default one.
- mHandlers.add(new DefaultTransitionHandler(pool, mainExecutor, animExecutor));
+ mHandlers.add(new DefaultTransitionHandler(pool, context, mainExecutor, animExecutor));
// Next lowest priority is remote transitions.
mRemoteTransitionHandler = new RemoteTransitionHandler(mainExecutor);
mHandlers.add(mRemoteTransitionHandler);
+
+ ContentResolver resolver = context.getContentResolver();
+ mTransitionAnimationScaleSetting = Settings.Global.getFloat(resolver,
+ Settings.Global.TRANSITION_ANIMATION_SCALE,
+ context.getResources().getFloat(
+ R.dimen.config_appTransitionAnimationDurationScaleDefault));
+ dispatchAnimScaleSetting(mTransitionAnimationScaleSetting);
+
+ resolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.TRANSITION_ANIMATION_SCALE), false,
+ new SettingsObserver());
}
private Transitions() {
mOrganizer = null;
+ mContext = null;
mMainExecutor = null;
mAnimExecutor = null;
mPlayerImpl = null;
mRemoteTransitionHandler = null;
}
+ private void dispatchAnimScaleSetting(float scale) {
+ for (int i = mHandlers.size() - 1; i >= 0; --i) {
+ mHandlers.get(i).setAnimScaleSetting(scale);
+ }
+ }
+
/** Create an empty/non-registering transitions object for system-ui tests. */
@VisibleForTesting
public static RemoteTransitions createEmptyForTesting() {
@@ -368,6 +396,13 @@ public class Transitions {
@Nullable
WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@NonNull TransitionRequestInfo request);
+
+ /**
+ * Sets transition animation scale settings value to handler.
+ *
+ * @param scale The setting value of transition animation scale.
+ */
+ default void setAnimScaleSetting(float scale) {}
}
@BinderThread
@@ -404,4 +439,21 @@ public class Transitions {
});
}
}
+
+ private class SettingsObserver extends ContentObserver {
+
+ SettingsObserver() {
+ super(null);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ mTransitionAnimationScaleSetting = Settings.Global.getFloat(
+ mContext.getContentResolver(), Settings.Global.TRANSITION_ANIMATION_SCALE,
+ mTransitionAnimationScaleSetting);
+
+ mMainExecutor.execute(() -> dispatchAnimScaleSetting(mTransitionAnimationScaleSetting));
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index a57ac35583b2..9dd25fe0e6fe 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test {
name: "WMShellFlickerTests",
srcs: ["src/**/*.java", "src/**/*.kt"],
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index 3282ece999ac..10aea519f18b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -18,239 +18,92 @@ package com.android.wm.shell.flicker
import android.graphics.Region
import android.view.Surface
-import com.android.server.wm.flicker.dsl.LayersAssertionBuilder
-import com.android.server.wm.flicker.dsl.LayersAssertionBuilderLegacy
import com.android.server.wm.flicker.APP_PAIR_SPLIT_DIVIDER
import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
+import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.traces.layers.getVisibleBounds
-@JvmOverloads
-fun LayersAssertionBuilder.appPairsDividerIsVisible(bugId: Int = 0) {
- end("appPairsDividerIsVisible", bugId) {
+fun FlickerTestParameter.appPairsDividerIsVisible() {
+ assertLayersEnd {
this.isVisible(APP_PAIR_SPLIT_DIVIDER)
}
}
-@JvmOverloads
-fun LayersAssertionBuilder.appPairsDividerIsInvisible(bugId: Int = 0) {
- end("appPairsDividerIsInVisible", bugId) {
+fun FlickerTestParameter.appPairsDividerIsInvisible() {
+ assertLayersEnd {
this.notExists(APP_PAIR_SPLIT_DIVIDER)
}
}
-@JvmOverloads
-fun LayersAssertionBuilder.appPairsDividerBecomesVisible(bugId: Int = 0) {
- all("dividerLayerBecomesVisible", bugId) {
+fun FlickerTestParameter.appPairsDividerBecomesVisible() {
+ assertLayers {
this.hidesLayer(DOCKED_STACK_DIVIDER)
.then()
.showsLayer(DOCKED_STACK_DIVIDER)
}
}
-@JvmOverloads
-fun LayersAssertionBuilder.dockedStackDividerIsVisible(bugId: Int = 0) {
- end("dockedStackDividerIsVisible", bugId) {
+fun FlickerTestParameter.dockedStackDividerIsVisible() {
+ assertLayersEnd {
this.isVisible(DOCKED_STACK_DIVIDER)
}
}
-@JvmOverloads
-fun LayersAssertionBuilder.dockedStackDividerBecomesVisible(bugId: Int = 0) {
- all("dividerLayerBecomesVisible", bugId) {
+fun FlickerTestParameter.dockedStackDividerBecomesVisible() {
+ assertLayers {
this.hidesLayer(DOCKED_STACK_DIVIDER)
.then()
.showsLayer(DOCKED_STACK_DIVIDER)
}
}
-@JvmOverloads
-fun LayersAssertionBuilder.dockedStackDividerBecomesInvisible(bugId: Int = 0) {
- all("dividerLayerBecomesInvisible", bugId) {
+fun FlickerTestParameter.dockedStackDividerBecomesInvisible() {
+ assertLayers {
this.showsLayer(DOCKED_STACK_DIVIDER)
.then()
.hidesLayer(DOCKED_STACK_DIVIDER)
}
}
-@JvmOverloads
-fun LayersAssertionBuilder.dockedStackDividerIsInvisible(bugId: Int = 0) {
- end("dockedStackDividerIsInvisible", bugId) {
+fun FlickerTestParameter.dockedStackDividerIsInvisible() {
+ assertLayersEnd {
this.notExists(DOCKED_STACK_DIVIDER)
}
}
-@JvmOverloads
-fun LayersAssertionBuilder.appPairsPrimaryBoundsIsVisible(
- rotation: Int,
- primaryLayerName: String,
- bugId: Int = 0
-) {
- end("PrimaryAppBounds", bugId) {
- val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
- this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation))
- }
-}
-
-@JvmOverloads
-fun LayersAssertionBuilder.appPairsSecondaryBoundsIsVisible(
- rotation: Int,
- secondaryLayerName: String,
- bugId: Int = 0
-) {
- end("SecondaryAppBounds", bugId) {
+fun FlickerTestParameter.appPairsPrimaryBoundsIsVisible(rotation: Int, primaryLayerName: String) {
+ assertLayersEnd {
val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
- this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation))
- }
-}
-
-@JvmOverloads
-fun LayersAssertionBuilder.dockedStackPrimaryBoundsIsVisible(
- rotation: Int,
- primaryLayerName: String,
- bugId: Int = 0
-) {
- end("PrimaryAppBounds", bugId) {
- val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER)
this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation))
}
}
-@JvmOverloads
-fun LayersAssertionBuilder.dockedStackSecondaryBoundsIsVisible(
+fun FlickerTestParameter.dockedStackPrimaryBoundsIsVisible(
rotation: Int,
- secondaryLayerName: String,
- bugId: Int = 0
+ primaryLayerName: String
) {
- end("SecondaryAppBounds", bugId) {
+ assertLayersEnd {
val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER)
- this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation))
- }
-}
-
-@JvmOverloads
-fun LayersAssertionBuilderLegacy.appPairsDividerIsVisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- end("appPairsDividerIsVisible", bugId, enabled) {
- this.isVisible(APP_PAIR_SPLIT_DIVIDER)
- }
-}
-
-@JvmOverloads
-fun LayersAssertionBuilderLegacy.appPairsDividerIsInvisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- end("appPairsDividerIsInVisible", bugId, enabled) {
- this.notExists(APP_PAIR_SPLIT_DIVIDER)
- }
-}
-
-@JvmOverloads
-fun LayersAssertionBuilderLegacy.appPairsDividerBecomesVisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("dividerLayerBecomesVisible", bugId, enabled) {
- this.hidesLayer(DOCKED_STACK_DIVIDER)
- .then()
- .showsLayer(DOCKED_STACK_DIVIDER)
- }
-}
-
-@JvmOverloads
-fun LayersAssertionBuilderLegacy.dockedStackDividerIsVisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- end("dockedStackDividerIsVisible", bugId, enabled) {
- this.isVisible(DOCKED_STACK_DIVIDER)
- }
-}
-
-@JvmOverloads
-fun LayersAssertionBuilderLegacy.dockedStackDividerBecomesVisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("dividerLayerBecomesVisible", bugId, enabled) {
- this.hidesLayer(DOCKED_STACK_DIVIDER)
- .then()
- .showsLayer(DOCKED_STACK_DIVIDER)
- }
-}
-
-@JvmOverloads
-fun LayersAssertionBuilderLegacy.dockedStackDividerBecomesInvisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("dividerLayerBecomesInvisible", bugId, enabled) {
- this.showsLayer(DOCKED_STACK_DIVIDER)
- .then()
- .hidesLayer(DOCKED_STACK_DIVIDER)
- }
-}
-
-@JvmOverloads
-fun LayersAssertionBuilderLegacy.dockedStackDividerIsInvisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- end("dockedStackDividerIsInvisible", bugId, enabled) {
- this.notExists(DOCKED_STACK_DIVIDER)
- }
-}
-
-@JvmOverloads
-fun LayersAssertionBuilderLegacy.appPairsPrimaryBoundsIsVisible(
- rotation: Int,
- primaryLayerName: String,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- end("PrimaryAppBounds", bugId, enabled) {
- val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation))
}
}
-@JvmOverloads
-fun LayersAssertionBuilderLegacy.appPairsSecondaryBoundsIsVisible(
+fun FlickerTestParameter.appPairsSecondaryBoundsIsVisible(
rotation: Int,
- secondaryLayerName: String,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
+ secondaryLayerName: String
) {
- end("SecondaryAppBounds", bugId, enabled) {
+ assertLayersEnd {
val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation))
}
}
-@JvmOverloads
-fun LayersAssertionBuilderLegacy.dockedStackPrimaryBoundsIsVisible(
+fun FlickerTestParameter.dockedStackSecondaryBoundsIsVisible(
rotation: Int,
- primaryLayerName: String,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
+ secondaryLayerName: String
) {
- end("PrimaryAppBounds", bugId, enabled) {
- val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER)
- this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation))
- }
-}
-
-@JvmOverloads
-fun LayersAssertionBuilderLegacy.dockedStackSecondaryBoundsIsVisible(
- rotation: Int,
- secondaryLayerName: String,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- end("SecondaryAppBounds", bugId, enabled) {
+ assertLayersEnd {
val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER)
this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation))
}
@@ -260,10 +113,10 @@ fun getPrimaryRegion(dividerRegion: Region, rotation: Int): Region {
val displayBounds = WindowUtils.getDisplayBounds(rotation)
return if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
Region(0, 0, displayBounds.bounds.right,
- dividerRegion.bounds.bottom - WindowUtils.dockedStackDividerInset)
+ dividerRegion.bounds.bottom - WindowUtils.dockedStackDividerInset)
} else {
Region(0, 0, dividerRegion.bounds.left,
- dividerRegion.bounds.right - WindowUtils.dockedStackDividerInset)
+ dividerRegion.bounds.right - WindowUtils.dockedStackDividerInset)
}
}
@@ -271,12 +124,12 @@ fun getSecondaryRegion(dividerRegion: Region, rotation: Int): Region {
val displayBounds = WindowUtils.getDisplayBounds(rotation)
return if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
Region(0,
- dividerRegion.bounds.bottom - WindowUtils.dockedStackDividerInset,
- displayBounds.bounds.right,
- displayBounds.bounds.bottom - WindowUtils.dockedStackDividerInset)
+ dividerRegion.bounds.bottom - WindowUtils.dockedStackDividerInset,
+ displayBounds.bounds.right,
+ displayBounds.bounds.bottom - WindowUtils.dockedStackDividerInset)
} else {
Region(dividerRegion.bounds.right, 0,
- displayBounds.bounds.right,
- displayBounds.bounds.bottom - WindowUtils.dockedStackDividerInset)
+ displayBounds.bounds.right,
+ displayBounds.bounds.bottom - WindowUtils.dockedStackDividerInset)
}
-}
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt
index 89bbdb0a2f99..9c50630095be 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt
@@ -16,33 +16,33 @@
package com.android.wm.shell.flicker
+import android.app.Instrumentation
import android.content.pm.PackageManager
import android.content.pm.PackageManager.FEATURE_LEANBACK
import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY
-import android.os.RemoteException
-import android.os.SystemClock
-import android.platform.helpers.IAppHelper
import android.view.Surface
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
-import com.android.server.wm.flicker.Flicker
import org.junit.Assume.assumeFalse
import org.junit.Before
+import org.junit.runners.Parameterized
/**
* Base class of all Flicker test that performs common functions for all flicker tests:
*
- *
* - Caches transitions so that a transition is run once and the transition results are used by
* tests multiple times. This is needed for parameterized tests which call the BeforeClass methods
* multiple times.
* - Keeps track of all test artifacts and deletes ones which do not need to be reviewed.
* - Fails tests if results are not available for any test due to jank.
*/
-abstract class FlickerTestBase {
- val instrumentation by lazy { InstrumentationRegistry.getInstrumentation() }
- val uiDevice by lazy { UiDevice.getInstance(instrumentation) }
- val packageManager: PackageManager by lazy { instrumentation.context.getPackageManager() }
+abstract class FlickerTestBase(
+ protected val rotationName: String,
+ protected val rotation: Int
+) {
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val uiDevice = UiDevice.getInstance(instrumentation)
+ val packageManager: PackageManager = instrumentation.context.packageManager
protected val isTelevision: Boolean by lazy {
packageManager.run {
hasSystemFeature(FEATURE_LEANBACK) || hasSystemFeature(FEATURE_LEANBACK_ONLY)
@@ -56,83 +56,12 @@ abstract class FlickerTestBase {
@Before
open fun televisionSetUp() = assumeFalse(isTelevision)
- /**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param app App being launcher
- * @param rotation Initial screen rotation
- *
- * @return test tag with pattern <NAME>__<APP>__<ROTATION>
- </ROTATION></APP></NAME> */
- protected fun buildTestTag(testName: String, app: IAppHelper, rotation: Int): String {
- return buildTestTag(
- testName, app, rotation, rotation, app2 = null, extraInfo = "")
- }
-
- /**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param app App being launcher
- * @param beginRotation Initial screen rotation
- * @param endRotation End screen rotation (if any, otherwise use same as initial)
- *
- * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
- </END_ROTATION></BEGIN_ROTATION></APP></NAME> */
- protected fun buildTestTag(
- testName: String,
- app: IAppHelper,
- beginRotation: Int,
- endRotation: Int
- ): String {
- return buildTestTag(
- testName, app, beginRotation, endRotation, app2 = null, extraInfo = "")
- }
-
- /**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param app App being launcher
- * @param app2 Second app being launched (if any)
- * @param beginRotation Initial screen rotation
- * @param endRotation End screen rotation (if any, otherwise use same as initial)
- * @param extraInfo Additional information to append to the tag
- *
- * @return test tag with pattern <NAME>__<APP></APP>(S)>__<ROTATION></ROTATION>(S)>[__<EXTRA>]
- </EXTRA></NAME> */
- protected fun buildTestTag(
- testName: String,
- app: IAppHelper,
- beginRotation: Int,
- endRotation: Int,
- app2: IAppHelper?,
- extraInfo: String
- ): String {
- var testTag = "${testName}__${app.launcherName}"
- if (app2 != null) {
- testTag += "-${app2.launcherName}"
- }
- testTag += "__${Surface.rotationToString(beginRotation)}"
- if (endRotation != beginRotation) {
- testTag += "-${Surface.rotationToString(endRotation)}"
- }
- if (extraInfo.isNotEmpty()) {
- testTag += "__$extraInfo"
- }
- return testTag
- }
-
- protected fun Flicker.setRotation(rotation: Int) {
- try {
- when (rotation) {
- Surface.ROTATION_270 -> device.setOrientationLeft()
- Surface.ROTATION_90 -> device.setOrientationRight()
- Surface.ROTATION_0 -> device.setOrientationNatural()
- else -> device.setOrientationNatural()
- }
- // Wait for animation to complete
- SystemClock.sleep(1000)
- } catch (e: RemoteException) {
- throw RuntimeException(e)
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
+ return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NonRotationTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NonRotationTestBase.kt
deleted file mode 100644
index 90334ae91e9d..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NonRotationTestBase.kt
+++ /dev/null
@@ -1,36 +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.flicker
-
-import android.view.Surface
-import org.junit.runners.Parameterized
-
-abstract class NonRotationTestBase(
- protected val rotationName: String,
- protected val rotation: Int
-) : FlickerTestBase() {
- companion object {
- const val SCREENSHOT_LAYER = "RotationLayer"
-
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
- return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
index c3fd66395366..5d51b2fd515f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
@@ -18,15 +18,16 @@ package com.android.wm.shell.flicker.apppairs
import android.os.Bundle
import android.os.SystemClock
+import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.buildTestTag
-import com.android.wm.shell.flicker.helpers.AppPairsHelper
import com.android.wm.shell.flicker.appPairsDividerIsInvisible
+import com.android.wm.shell.flicker.helpers.AppPairsHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -41,47 +42,47 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class AppPairsTestCannotPairNonResizeableApps(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : AppPairsTransition(InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag(configuration)
- }
- transitions {
- nonResizeableApp?.launchViaIntent(wmHelper)
- // TODO pair apps through normal UX flow
- executeShellCommand(
- composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true))
- SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
- }
- assertions {
- presubmit {
- layersTrace {
- appPairsDividerIsInvisible()
- }
- windowManagerTrace {
- val nonResizeableApp = nonResizeableApp
- require(nonResizeableApp != null) {
- "Non resizeable app not initialized"
- }
+ testSpec: FlickerTestParameter
+) : AppPairsTransition(testSpec) {
- end("onlyResizeableAppWindowVisible") {
- isVisible(nonResizeableApp.defaultWindowName)
- isInvisible(primaryApp.defaultWindowName)
- }
- }
- }
- }
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = {
+ super.transition(this, it)
+ transitions {
+ nonResizeableApp?.launchViaIntent(wmHelper)
+ // TODO pair apps through normal UX flow
+ executeShellCommand(
+ composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true))
+ SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
}
+ }
+
+ @Presubmit
+ @Test
+ fun appPairsDividerIsInvisible() = testSpec.appPairsDividerIsInvisible()
- return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation,
- transition, testSpec, repetitions = AppPairsHelper.TEST_REPETITIONS)
+ @Presubmit
+ @Test
+ fun onlyResizeableAppWindowVisible() {
+ val nonResizeableApp = nonResizeableApp
+ require(nonResizeableApp != null) {
+ "Non resizeable app not initialized"
+ }
+ testSpec.assertWmEnd {
+ isVisible(nonResizeableApp.defaultWindowName)
+ isInvisible(primaryApp.defaultWindowName)
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+ repetitions = AppPairsHelper.TEST_REPETITIONS)
}
}
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
index 7a2a5e482d98..77890ba8ed15 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
@@ -18,17 +18,19 @@ package com.android.wm.shell.flicker.apppairs
import android.os.Bundle
import android.os.SystemClock
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.APP_PAIR_SPLIT_DIVIDER
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.traces.layers.getVisibleBounds
import com.android.wm.shell.flicker.appPairsDividerIsVisible
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,52 +41,53 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class AppPairsTestPairPrimaryAndSecondaryApps(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : AppPairsTransition(InstrumentationRegistry.getInstrumentation()) {
+ testSpec: FlickerTestParameter
+) : AppPairsTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = {
+ super.transition(this, it)
+ transitions {
+ // TODO pair apps through normal UX flow
+ executeShellCommand(
+ composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
+ SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
+
+ @Presubmit
+ @Test
+ fun bothAppWindowsVisible() {
+ testSpec.assertWmEnd {
+ isVisible(primaryApp.defaultWindowName)
+ isVisible(secondaryApp.defaultWindowName)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ fun appsEndingBounds() {
+ testSpec.assertLayersEnd {
+ val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
+ this.hasVisibleRegion(primaryApp.defaultWindowName,
+ appPairsHelper.getPrimaryBounds(dividerRegion))
+ .hasVisibleRegion(secondaryApp.defaultWindowName,
+ appPairsHelper.getSecondaryBounds(dividerRegion))
+ }
+ }
+
+ companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag(configuration)
- }
- transitions {
- // TODO pair apps through normal UX flow
- executeShellCommand(
- composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
- SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
- }
- assertions {
- presubmit {
- layersTrace {
- appPairsDividerIsVisible()
- }
- windowManagerTrace {
- end("bothAppWindowsVisible") {
- isVisible(primaryApp.defaultWindowName)
- isVisible(secondaryApp.defaultWindowName)
- }
- }
- }
-
- flaky {
- layersTrace {
- end("appsEndingBounds") {
- val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
- this.hasVisibleRegion(primaryApp.defaultWindowName,
- appPairsHelper.getPrimaryBounds(dividerRegion))
- .hasVisibleRegion(secondaryApp.defaultWindowName,
- appPairsHelper.getSecondaryBounds(dividerRegion))
- }
- }
- }
- }
- }
- return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, transition,
- testSpec, repetitions = AppPairsHelper.TEST_REPETITIONS)
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+ repetitions = AppPairsHelper.TEST_REPETITIONS)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
index d8dc4c2b56f6..3d3ca0cfd450 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
@@ -18,17 +18,19 @@ package com.android.wm.shell.flicker.apppairs
import android.os.Bundle
import android.os.SystemClock
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.APP_PAIR_SPLIT_DIVIDER
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.traces.layers.getVisibleBounds
import com.android.wm.shell.flicker.appPairsDividerIsInvisible
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,61 +41,67 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class AppPairsTestUnpairPrimaryAndSecondaryApps(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : AppPairsTransition(InstrumentationRegistry.getInstrumentation()) {
+ testSpec: FlickerTestParameter
+) : AppPairsTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = {
+ super.transition(this, it)
+ setup {
+ executeShellCommand(
+ composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
+ SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+ }
+ transitions {
+ // TODO pair apps through normal UX flow
+ executeShellCommand(
+ composePairsCommand(primaryTaskId, secondaryTaskId, pair = false))
+ SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun appPairsDividerIsInvisible() = testSpec.appPairsDividerIsInvisible()
+
+ @Presubmit
+ @Test
+ fun bothAppWindowsInvisible() {
+ testSpec.assertWmEnd {
+ isInvisible(primaryApp.defaultWindowName)
+ isInvisible(secondaryApp.defaultWindowName)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ fun appsStartingBounds() {
+ testSpec.assertLayersStart {
+ val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
+ hasVisibleRegion(primaryApp.defaultWindowName,
+ appPairsHelper.getPrimaryBounds(dividerRegion))
+ hasVisibleRegion(secondaryApp.defaultWindowName,
+ appPairsHelper.getSecondaryBounds(dividerRegion))
+ }
+ }
+
+ @FlakyTest
+ @Test
+ fun appsEndingBounds() {
+ testSpec.assertLayersEnd {
+ notExists(primaryApp.defaultWindowName)
+ notExists(secondaryApp.defaultWindowName)
+ }
+ }
+
+ companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag(configuration)
- }
- setup {
- executeShellCommand(
- composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
- SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
- }
- transitions {
- // TODO pair apps through normal UX flow
- executeShellCommand(
- composePairsCommand(primaryTaskId, secondaryTaskId, pair = false))
- SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
- }
- assertions {
- presubmit {
- layersTrace {
- appPairsDividerIsInvisible()
- }
- windowManagerTrace {
- end("bothAppWindowsInvisible") {
- isInvisible(primaryApp.defaultWindowName)
- isInvisible(secondaryApp.defaultWindowName)
- }
- }
- }
-
- flaky {
- layersTrace {
- start("appsStartingBounds") {
- val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
- this.hasVisibleRegion(primaryApp.defaultWindowName,
- appPairsHelper.getPrimaryBounds(dividerRegion))
- .hasVisibleRegion(secondaryApp.defaultWindowName,
- appPairsHelper.getSecondaryBounds(dividerRegion))
- }
- end("appsEndingBounds") {
- this.notExists(primaryApp.defaultWindowName)
- .notExists(secondaryApp.defaultWindowName)
- }
- }
- }
- }
- }
- return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, transition,
- testSpec, repetitions = AppPairsHelper.TEST_REPETITIONS)
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+ repetitions = AppPairsHelper.TEST_REPETITIONS)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
index 78a938aef69e..9e6752db224f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
@@ -18,38 +18,53 @@ package com.android.wm.shell.flicker.apppairs
import android.app.Instrumentation
import android.os.Bundle
+import android.platform.test.annotations.Presubmit
import android.system.helpers.ActivityHelper
import android.util.Log
+import androidx.test.platform.app.InstrumentationRegistry
import com.android.compatibility.common.util.SystemUtil
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import com.android.wm.shell.flicker.testapp.Components
+import org.junit.Test
import java.io.IOException
-open class AppPairsTransition(
- protected val instrumentation: Instrumentation
-) {
- internal val activityHelper = ActivityHelper.getInstance()
-
- internal val appPairsHelper = AppPairsHelper(instrumentation,
+abstract class AppPairsTransition(protected val testSpec: FlickerTestParameter) {
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ protected val isRotated = testSpec.config.startRotation.isRotated()
+ protected val activityHelper = ActivityHelper.getInstance()
+ protected val appPairsHelper = AppPairsHelper(instrumentation,
Components.SplitScreenActivity.LABEL,
Components.SplitScreenActivity.COMPONENT)
- internal val primaryApp = SplitScreenHelper.getPrimary(instrumentation)
- internal val secondaryApp = SplitScreenHelper.getSecondary(instrumentation)
- internal open val nonResizeableApp: SplitScreenHelper? =
+ protected val primaryApp = SplitScreenHelper.getPrimary(instrumentation)
+ protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation)
+ protected open val nonResizeableApp: SplitScreenHelper? =
SplitScreenHelper.getNonResizeable(instrumentation)
- internal var primaryTaskId = ""
- internal var secondaryTaskId = ""
- internal var nonResizeableTaskId = ""
+ protected var primaryTaskId = ""
+ protected var secondaryTaskId = ""
+ protected var nonResizeableTaskId = ""
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ transition(this, testSpec.config)
+ }
+ }
internal open val transition: FlickerBuilder.(Bundle) -> Unit
get() = { configuration ->
@@ -71,20 +86,9 @@ open class AppPairsTransition(
primaryTaskId, secondaryTaskId, pair = false))
executeShellCommand(composePairsCommand(
primaryTaskId, nonResizeableTaskId, pair = false))
- primaryApp.exit()
- secondaryApp.exit()
- nonResizeableApp?.exit()
- }
- }
-
- assertions {
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- }
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ nonResizeableApp?.exit(wmHelper)
}
}
}
@@ -128,4 +132,20 @@ open class AppPairsTransition(
}
append("$primaryApp $secondaryApp")
}
+
+ @Presubmit
+ @Test
+ open fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ open fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
index 8aee005b7513..35a0020b16a9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
@@ -18,25 +18,25 @@ package com.android.wm.shell.flicker.apppairs
import android.os.Bundle
import android.os.SystemClock
+import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.appPairsDividerIsVisible
import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisible
import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisible
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -47,57 +47,65 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class RotateTwoLaunchedAppsInAppPairsMode(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : RotateTwoLaunchedAppsTransition(
- InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag(configuration)
- }
- transitions {
- executeShellCommand(composePairsCommand(
- primaryTaskId, secondaryTaskId, true /* pair */))
- SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
- setRotation(configuration.endRotation)
- }
- assertions {
- presubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- end("bothAppWindowsVisible") {
- isVisible(primaryApp.defaultWindowName)
- .isVisible(secondaryApp.defaultWindowName)
- }
- }
- }
-
- flaky {
- layersTrace {
- appPairsDividerIsVisible()
- navBarLayerRotatesAndScales(Surface.ROTATION_0,
- configuration.endRotation)
- statusBarLayerRotatesScales(Surface.ROTATION_0,
- configuration.endRotation)
- appPairsPrimaryBoundsIsVisible(configuration.endRotation,
- primaryApp.defaultWindowName, bugId = 172776659)
- appPairsSecondaryBoundsIsVisible(configuration.endRotation,
- secondaryApp.defaultWindowName, bugId = 172776659)
- }
- }
- }
+ testSpec: FlickerTestParameter
+) : RotateTwoLaunchedAppsTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = {
+ super.transition(this, it)
+ transitions {
+ executeShellCommand(composePairsCommand(
+ primaryTaskId, secondaryTaskId, true /* pair */))
+ SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+ setRotation(testSpec.config.endRotation)
}
+ }
+
+ @Presubmit
+ @Test
+ fun bothAppWindowsVisible() {
+ testSpec.assertWmEnd {
+ isVisible(primaryApp.defaultWindowName)
+ .isVisible(secondaryApp.defaultWindowName)
+ }
+ }
- return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation,
- transition, testSpec,
+ @FlakyTest
+ @Test
+ fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ testSpec.config.endRotation)
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0,
+ testSpec.config.endRotation)
+
+ @FlakyTest(bugId = 172776659)
+ @Test
+ fun appPairsPrimaryBoundsIsVisible() =
+ testSpec.appPairsPrimaryBoundsIsVisible(testSpec.config.endRotation,
+ primaryApp.defaultWindowName)
+
+ @FlakyTest(bugId = 172776659)
+ @Test
+ fun appPairsSecondaryBoundsIsVisible() =
+ testSpec.appPairsSecondaryBoundsIsVisible(testSpec.config.endRotation,
+ secondaryApp.defaultWindowName)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_90, Surface.ROTATION_270))
+ supportedRotations = listOf(Surface.ROTATION_90, Surface.ROTATION_270)
+ )
}
}
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
index bc99c9430f13..326a775acc8d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
@@ -20,18 +20,16 @@ import android.os.Bundle
import android.os.SystemClock
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
-import com.android.server.wm.flicker.helpers.buildTestTag
-import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.appPairsDividerIsVisible
@@ -39,7 +37,9 @@ import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisible
import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisible
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.Assume
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -48,70 +48,84 @@ import org.junit.runners.Parameterized
* Test open apps to app pairs and rotate.
* To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppsRotateAndEnterAppPairsMode`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class RotateTwoLaunchedAppsRotateAndEnterAppPairsMode(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : RotateTwoLaunchedAppsTransition(
- InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag(configuration)
- }
- transitions {
- this.setRotation(configuration.endRotation)
- executeShellCommand(
- composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
- SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
- }
- assertions {
- val isRotated = configuration.startRotation.isRotated()
- presubmit {
- layersTrace {
- statusBarLayerRotatesScales(Surface.ROTATION_0,
- configuration.endRotation)
- appPairsDividerIsVisible()
- if (!isRotated) {
- navBarLayerRotatesAndScales(Surface.ROTATION_0,
- configuration.endRotation)
- }
- }
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- end("bothAppWindowsVisible") {
- isVisible(primaryApp.defaultWindowName)
- isVisible(secondaryApp.defaultWindowName)
- }
- }
- }
- flaky {
- layersTrace {
- appPairsPrimaryBoundsIsVisible(configuration.endRotation,
- primaryApp.defaultWindowName, 172776659)
- appPairsSecondaryBoundsIsVisible(configuration.endRotation,
- secondaryApp.defaultWindowName, 172776659)
-
- if (isRotated) {
- navBarLayerRotatesAndScales(Surface.ROTATION_0,
- configuration.endRotation)
- }
- }
- }
- }
+ testSpec: FlickerTestParameter
+) : RotateTwoLaunchedAppsTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = {
+ super.transition(this, it)
+ transitions {
+ this.setRotation(testSpec.config.endRotation)
+ executeShellCommand(
+ composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
+ SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
}
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0,
+ testSpec.config.endRotation)
+
+ @Presubmit
+ @Test
+ fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ Assume.assumeFalse(isRotated)
+ testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales_Flaky() {
+ Assume.assumeTrue(isRotated)
+ testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
- return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation,
- transition, testSpec,
+ @Presubmit
+ @Test
+ override fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ override fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun bothAppWindowsVisible() {
+ testSpec.assertWmEnd {
+ isVisible(primaryApp.defaultWindowName)
+ isVisible(secondaryApp.defaultWindowName)
+ }
+ }
+
+ @FlakyTest(bugId = 172776659)
+ @Test
+ fun appPairsPrimaryBoundsIsVisible() =
+ testSpec.appPairsPrimaryBoundsIsVisible(testSpec.config.endRotation,
+ primaryApp.defaultWindowName)
+
+ @FlakyTest(bugId = 172776659)
+ @Test
+ fun appPairsSecondaryBoundsIsVisible() =
+ testSpec.appPairsSecondaryBoundsIsVisible(testSpec.config.endRotation,
+ secondaryApp.defaultWindowName)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
repetitions = SplitScreenHelper.TEST_REPETITIONS,
supportedRotations = listOf(Surface.ROTATION_90, Surface.ROTATION_270)
)
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
index 8ea2544fcf61..271b25fc0ce1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
@@ -16,17 +16,17 @@
package com.android.wm.shell.flicker.apppairs
-import android.app.Instrumentation
import android.os.Bundle
import android.view.Surface
+import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-open class RotateTwoLaunchedAppsTransition(
- instrumentation: Instrumentation
-) : AppPairsTransition(instrumentation) {
+abstract class RotateTwoLaunchedAppsTransition(
+ testSpec: FlickerTestParameter
+) : AppPairsTransition(testSpec) {
override val nonResizeableApp: SplitScreenHelper?
get() = null
@@ -45,8 +45,8 @@ open class RotateTwoLaunchedAppsTransition(
eachRun {
executeShellCommand(composePairsCommand(
primaryTaskId, secondaryTaskId, pair = false))
- primaryApp.exit()
- secondaryApp.exit()
+ primaryApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
index 0d9edd29d259..9b70fac737e6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
@@ -19,13 +19,13 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.os.Bundle
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.WALLPAPER_TITLE
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.startRotation
@@ -36,6 +36,7 @@ import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible
import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -47,56 +48,74 @@ import org.junit.runners.Parameterized
@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
// @FlakyTest(bugId = 179116910)
class EnterSplitScreenDockActivity(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) {
+ testSpec: FlickerTestParameter
+) : LegacySplitScreenTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ super.transition(this, configuration)
+ transitions {
+ device.launchSplitScreen(wmHelper)
+ }
+ }
+
+ @FlakyTest(bugId = 169271943)
+ @Test
+ fun dockedStackPrimaryBoundsIsVisible() =
+ testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation,
+ splitScreenApp.defaultWindowName)
+
+ @Presubmit
+ @Test
+ fun dockedStackDividerBecomesVisible() = testSpec.dockedStackDividerBecomesVisible()
+
+ @FlakyTest(bugId = 178531736)
+ @Test
+ // b/178531736
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(LAUNCHER_PACKAGE_NAME,
+ WALLPAPER_TITLE, LIVE_WALLPAPER_PACKAGE_NAME,
+ splitScreenApp.defaultWindowName)
+ )
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @FlakyTest(bugId = 178531736)
+ @Test
+ // b/178531736
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(
+ listOf(LAUNCHER_PACKAGE_NAME,
+ WALLPAPER_TITLE, LIVE_WALLPAPER_PACKAGE_NAME,
+ splitScreenApp.defaultWindowName)
+ )
+
+ @Presubmit
+ @Test
+ fun appWindowIsVisible() {
+ testSpec.assertWmEnd {
+ isVisible(splitScreenApp.defaultWindowName)
+ }
+ }
+
+ companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag("testLegacySplitScreenDockActivity", configuration)
- }
- repeat { SplitScreenHelper.TEST_REPETITIONS }
- transitions {
- device.launchSplitScreen(wmHelper)
- }
- assertions {
- layersTrace {
- dockedStackPrimaryBoundsIsVisible(
- configuration.startRotation,
- splitScreenApp.defaultWindowName, bugId = 169271943)
- dockedStackDividerBecomesVisible()
- visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(LAUNCHER_PACKAGE_NAME,
- WALLPAPER_TITLE, LIVE_WALLPAPER_PACKAGE_NAME,
- splitScreenApp.defaultWindowName),
- bugId = 178531736
- )
- }
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry(
- listOf(LAUNCHER_PACKAGE_NAME,
- WALLPAPER_TITLE, LIVE_WALLPAPER_PACKAGE_NAME,
- splitScreenApp.defaultWindowName),
- bugId = 178531736
- )
- end("appWindowIsVisible") {
- isVisible(splitScreenApp.defaultWindowName)
- }
- }
- }
- }
- return FlickerTestRunnerFactory.getInstance().buildTest(
- instrumentation, defaultTransitionSetup, testSpec,
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
repetitions = SplitScreenHelper.TEST_REPETITIONS,
supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910
)
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
index a513ee1e91f1..bd57a59ea3d9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
@@ -19,13 +19,13 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.os.Bundle
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
@@ -38,6 +38,7 @@ import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -46,61 +47,79 @@ import org.junit.runners.Parameterized
* Test open activity to primary split screen and dock secondary activity to side
* To run this test: `atest WMShellFlickerTests:EnterSplitScreenLaunchToSide`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class EnterSplitScreenLaunchToSide(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) {
+ testSpec: FlickerTestParameter
+) : LegacySplitScreenTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ super.transition(this, configuration)
+ transitions {
+ device.launchSplitScreen(wmHelper)
+ device.reopenAppFromOverview(wmHelper)
+ }
+ }
+
+ @FlakyTest(bugId = 169271943)
+ @Test
+ fun dockedStackPrimaryBoundsIsVisible() =
+ testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation,
+ splitScreenApp.defaultWindowName)
+
+ @FlakyTest(bugId = 169271943)
+ @Test
+ fun dockedStackSecondaryBoundsIsVisible() =
+ testSpec.dockedStackSecondaryBoundsIsVisible(testSpec.config.startRotation,
+ secondaryApp.defaultWindowName)
+
+ @Presubmit
+ @Test
+ // b/169271943
+ fun dockedStackDividerBecomesVisible() = testSpec.dockedStackDividerBecomesVisible()
+
+ @FlakyTest(bugId = 178447631)
+ @Test
+ // TODO(b/178447631) Remove Splash Screen from white list when flicker lib
+ // add a wait for splash screen be gone
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(LAUNCHER_PACKAGE_NAME, SPLASH_SCREEN_NAME,
+ splitScreenApp.defaultWindowName,
+ secondaryApp.defaultWindowName)
+ )
+
+ @Presubmit
+ @Test
+ fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp.defaultWindowName)
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(
+ listOf(LAUNCHER_PACKAGE_NAME, SPLASH_SCREEN_NAME,
+ splitScreenApp.defaultWindowName,
+ secondaryApp.defaultWindowName)
+ )
+
+ companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag("testLegacySplitScreenLaunchToSide", configuration)
- }
- repeat { SplitScreenHelper.TEST_REPETITIONS }
- transitions {
- device.launchSplitScreen(wmHelper)
- device.reopenAppFromOverview(wmHelper)
- }
- assertions {
- layersTrace {
- dockedStackPrimaryBoundsIsVisible(
- configuration.startRotation,
- splitScreenApp.defaultWindowName, bugId = 169271943)
- dockedStackSecondaryBoundsIsVisible(
- configuration.startRotation,
- secondaryApp.defaultWindowName, bugId = 169271943)
- dockedStackDividerBecomesVisible()
- // TODO(b/178447631) Remove Splash Screen from white list when flicker lib
- // add a wait for splash screen be gone
- visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(LAUNCHER_PACKAGE_NAME, SPLASH_SCREEN_NAME,
- splitScreenApp.defaultWindowName,
- secondaryApp.defaultWindowName),
- bugId = 178447631
- )
- }
- windowManagerTrace {
- appWindowBecomesVisible(secondaryApp.defaultWindowName)
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry(
- listOf(LAUNCHER_PACKAGE_NAME, SPLASH_SCREEN_NAME,
- splitScreenApp.defaultWindowName,
- secondaryApp.defaultWindowName)
- )
- }
- }
- }
- return FlickerTestRunnerFactory.getInstance().buildTest(
- instrumentation, defaultTransitionSetup, testSpec,
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
repetitions = SplitScreenHelper.TEST_REPETITIONS,
supportedRotations = listOf(Surface.ROTATION_0) // bugId = 175687842
)
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt
index 78ed773f2409..67578b29a36c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt
@@ -17,16 +17,14 @@
package com.android.wm.shell.flicker.legacysplitscreen
import android.os.Bundle
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.WALLPAPER_TITLE
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.canSplitScreen
import com.android.server.wm.flicker.helpers.openQuickstep
import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
@@ -35,6 +33,7 @@ import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.Assert
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -43,64 +42,68 @@ import org.junit.runners.Parameterized
* Test open non-resizable activity will auto exit split screen mode
* To run this test: `atest WMShellFlickerTests:EnterSplitScreenNonResizableNotDock`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FlakyTest(bugId = 173875043)
class EnterSplitScreenNonResizableNotDock(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag("testLegacySplitScreenNonResizeableActivityNotDock", configuration)
- }
- repeat { SplitScreenHelper.TEST_REPETITIONS }
- teardown {
- eachRun {
- nonResizeableApp.exit(wmHelper)
- }
- }
- transitions {
- nonResizeableApp.launchViaIntent(wmHelper)
- device.openQuickstep(wmHelper)
- if (device.canSplitScreen(wmHelper)) {
- Assert.fail("Non-resizeable app should not enter split screen")
- }
+ testSpec: FlickerTestParameter
+) : LegacySplitScreenTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ super.transition(this, configuration)
+ teardown {
+ eachRun {
+ nonResizeableApp.exit(wmHelper)
}
- assertions {
- layersTrace {
- dockedStackDividerIsInvisible()
- visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(LAUNCHER_PACKAGE_NAME,
- SPLASH_SCREEN_NAME,
- nonResizeableApp.defaultWindowName,
- splitScreenApp.defaultWindowName),
- bugId = 178447631
- )
- }
- windowManagerTrace {
- visibleWindowsShownMoreThanOneConsecutiveEntry(
- listOf(WALLPAPER_TITLE,
- LAUNCHER_PACKAGE_NAME,
- SPLASH_SCREEN_NAME,
- nonResizeableApp.defaultWindowName,
- splitScreenApp.defaultWindowName)
- )
- end("appWindowIsVisible") {
- isInvisible(nonResizeableApp.defaultWindowName)
- }
- }
+ }
+ transitions {
+ nonResizeableApp.launchViaIntent(wmHelper)
+ device.openQuickstep(wmHelper)
+ if (device.canSplitScreen(wmHelper)) {
+ Assert.fail("Non-resizeable app should not enter split screen")
}
}
- return FlickerTestRunnerFactory.getInstance().buildTest(
- instrumentation, cleanSetup, testSpec,
+ }
+
+ @Test
+ fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible()
+
+ @FlakyTest(bugId = 178447631)
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(LAUNCHER_PACKAGE_NAME,
+ SPLASH_SCREEN_NAME,
+ nonResizeableApp.defaultWindowName,
+ splitScreenApp.defaultWindowName)
+ )
+
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(
+ listOf(WALLPAPER_TITLE,
+ LAUNCHER_PACKAGE_NAME,
+ SPLASH_SCREEN_NAME,
+ nonResizeableApp.defaultWindowName,
+ splitScreenApp.defaultWindowName)
+ )
+
+ @Test
+ fun appWindowIsVisible() {
+ testSpec.assertWmEnd {
+ isInvisible(nonResizeableApp.defaultWindowName)
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0 /* bugId = 178685668 */))
+ supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
}
}
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
index f4e5ba7877da..5d42a4a8fae0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
@@ -19,14 +19,14 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.os.Bundle
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.appWindowBecomesInVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.exitSplitScreenFromBottom
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.layerBecomesInvisible
@@ -36,6 +36,7 @@ import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEnt
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -44,61 +45,72 @@ import org.junit.runners.Parameterized
* Test open resizeable activity split in primary, and drag divider to bottom exit split screen
* To run this test: `atest WMShellFlickerTests:ExitLegacySplitScreenFromBottom`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class ExitLegacySplitScreenFromBottom(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag("testExitLegacySplitScreenFromBottom", configuration)
- }
- repeat { SplitScreenHelper.TEST_REPETITIONS }
- setup {
- eachRun {
- splitScreenApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- }
- }
- teardown {
- eachRun {
- splitScreenApp.exit(wmHelper)
- }
- }
- transitions {
- device.exitSplitScreenFromBottom()
+ testSpec: FlickerTestParameter
+) : LegacySplitScreenTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ super.transition(this, configuration)
+ setup {
+ eachRun {
+ splitScreenApp.launchViaIntent(wmHelper)
+ device.launchSplitScreen(wmHelper)
}
- assertions {
- layersTrace {
- layerBecomesInvisible(DOCKED_STACK_DIVIDER)
- visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
- secondaryApp.defaultWindowName),
- bugId = 178447631
- )
- }
- windowManagerTrace {
- appWindowBecomesInVisible(secondaryApp.defaultWindowName)
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry(
- listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
- secondaryApp.defaultWindowName),
- bugId = 178447631
- )
- }
+ }
+ teardown {
+ eachRun {
+ splitScreenApp.exit(wmHelper)
}
}
- return FlickerTestRunnerFactory.getInstance().buildTest(
- instrumentation, defaultTransitionSetup, testSpec,
+ transitions {
+ device.exitSplitScreenFromBottom()
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(DOCKED_STACK_DIVIDER)
+
+ @FlakyTest(bugId = 178447631)
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
+ secondaryApp.defaultWindowName)
+ )
+
+ @Presubmit
+ @Test
+ fun appWindowBecomesInVisible() =
+ testSpec.appWindowBecomesInVisible(secondaryApp.defaultWindowName)
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @FlakyTest(bugId = 178447631)
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(
+ listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
+ secondaryApp.defaultWindowName)
+ )
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0) // bugId = 175687842
+ supportedRotations = listOf(Surface.ROTATION_0) // b/175687842
)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
index 8737fc5f8430..ff8f9c6ed865 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
@@ -17,14 +17,15 @@
package com.android.wm.shell.flicker.legacysplitscreen
import android.os.Bundle
+import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.appWindowBecomesInVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.layerBecomesInvisible
@@ -35,6 +36,7 @@ import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEn
import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -46,56 +48,71 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class ExitPrimarySplitScreenShowSecondaryFullscreen(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag("testExitPrimarySplitScreenShowSecondaryFullscreen", configuration)
- }
- repeat { SplitScreenHelper.TEST_REPETITIONS }
- teardown {
- eachRun {
- secondaryApp.exit(wmHelper)
- }
- }
- transitions {
- splitScreenApp.launchViaIntent(wmHelper)
- secondaryApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- device.reopenAppFromOverview(wmHelper)
- // TODO(b/175687842) Can not find Split screen divider, use exit() instead
- splitScreenApp.exit(wmHelper)
- }
- assertions {
- layersTrace {
- dockedStackDividerIsInvisible(bugId = 175687842)
- layerBecomesInvisible(splitScreenApp.defaultWindowName)
- visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
- secondaryApp.defaultWindowName),
- bugId = 178447631
- )
- }
- windowManagerTrace {
- appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry(
- listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
- secondaryApp.defaultWindowName),
- bugId = 178447631
- )
- }
+ testSpec: FlickerTestParameter
+) : LegacySplitScreenTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ super.transition(this, configuration)
+ teardown {
+ eachRun {
+ secondaryApp.exit(wmHelper)
}
}
- return FlickerTestRunnerFactory.getInstance().buildTest(
- instrumentation, defaultTransitionSetup, testSpec,
+ transitions {
+ splitScreenApp.launchViaIntent(wmHelper)
+ secondaryApp.launchViaIntent(wmHelper)
+ device.launchSplitScreen(wmHelper)
+ device.reopenAppFromOverview(wmHelper)
+ // TODO(b/175687842) Can not find Split screen divider, use exit() instead
+ splitScreenApp.exit(wmHelper)
+ }
+ }
+
+ @FlakyTest(bugId = 175687842)
+ @Test
+ fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible()
+
+ @Presubmit
+ @Test
+ fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+
+ @FlakyTest(bugId = 178447631)
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
+ secondaryApp.defaultWindowName)
+ )
+
+ @Presubmit
+ @Test
+ fun appWindowBecomesInVisible() =
+ testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @FlakyTest(bugId = 178447631)
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(
+ listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
+ secondaryApp.defaultWindowName)
+ )
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
repetitions = SplitScreenHelper.TEST_REPETITIONS,
supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910
)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt
new file mode 100644
index 000000000000..893b101d0759
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.legacysplitscreen
+
+import android.os.Bundle
+import android.view.Surface
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+
+abstract class LegacySplitScreenRotateTransition(
+ testSpec: FlickerTestParameter
+) : LegacySplitScreenTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = {
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ device.openQuickStepAndClearRecentAppsFromOverview(wmHelper)
+ secondaryApp.launchViaIntent(wmHelper)
+ splitScreenApp.launchViaIntent(wmHelper)
+ }
+ }
+ teardown {
+ eachRun {
+ splitScreenApp.exit(wmHelper)
+ secondaryApp.exit(wmHelper)
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
index c0feaee73d9a..09a7e31d20e2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
@@ -16,18 +16,19 @@
package com.android.wm.shell.flicker.legacysplitscreen
+import android.os.Bundle
import android.platform.test.annotations.Presubmit
import android.support.test.launcherhelper.LauncherStrategyFactory
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusDoesNotChange
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.exitSplitScreen
-import com.android.server.wm.flicker.helpers.isInSplitScreen
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
import com.android.server.wm.flicker.helpers.setRotation
@@ -39,13 +40,13 @@ import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEnt
import com.android.server.wm.flicker.layerBecomesInvisible
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.dockedStackDividerBecomesInvisible
import com.android.wm.shell.flicker.helpers.SimpleAppHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -54,80 +55,100 @@ import org.junit.runners.Parameterized
* Test open app to split screen.
* To run this test: `atest WMShellFlickerTests:LegacySplitScreenToLauncher`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class LegacySplitScreenToLauncher(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val launcherPackageName = LauncherStrategyFactory.getInstance(instrumentation)
- .launcherStrategy.supportedLauncherPackage
- val testApp = SimpleAppHelper(instrumentation)
+ testSpec: FlickerTestParameter
+) : LegacySplitScreenTransition(testSpec) {
+ private val launcherPackageName = LauncherStrategyFactory.getInstance(instrumentation)
+ .launcherStrategy.supportedLauncherPackage
+ private val testApp = SimpleAppHelper(instrumentation)
- // b/161435597 causes the test not to work on 90 degrees
- return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation,
- supportedRotations = listOf(Surface.ROTATION_0)) { configuration ->
- withTestName {
- buildTestTag("splitScreenToLauncher", configuration)
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ device.openQuickStepAndClearRecentAppsFromOverview(wmHelper)
}
- repeat { configuration.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- device.openQuickStepAndClearRecentAppsFromOverview(wmHelper)
- }
- eachRun {
- testApp.launchViaIntent(wmHelper)
- this.setRotation(configuration.endRotation)
- device.launchSplitScreen(wmHelper)
- }
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ this.setRotation(configuration.endRotation)
+ device.launchSplitScreen(wmHelper)
+ device.waitForIdle()
}
- teardown {
- eachRun {
- testApp.exit()
- }
- test {
- if (device.isInSplitScreen()) {
- device.exitSplitScreen()
- }
- }
- }
- transitions {
- device.exitSplitScreen()
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry()
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(configuration.endRotation)
- navBarLayerRotatesAndScales(configuration.endRotation)
- statusBarLayerRotatesScales(configuration.endRotation)
- visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(launcherPackageName))
-
- // b/161435597 causes the test not to work on 90 degrees
- dockedStackDividerBecomesInvisible()
-
- layerBecomesInvisible(testApp.getPackage())
- }
-
- eventLog {
- focusDoesNotChange(bugId = 151179149)
- }
+ }
+ teardown {
+ eachRun {
+ testApp.exit(wmHelper)
}
}
+ transitions {
+ device.exitSplitScreen()
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.endRotation)
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() =
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.endRotation)
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() =
+ testSpec.statusBarLayerRotatesScales(testSpec.config.endRotation)
+
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(listOf(launcherPackageName))
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun dockedStackDividerBecomesInvisible() = testSpec.dockedStackDividerBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(testApp.getPackage())
+
+ @FlakyTest(bugId = 151179149)
+ @Test
+ fun focusDoesNotChange() = testSpec.focusDoesNotChange()
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ // b/161435597 causes the test not to work on 90 degrees
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
index f9d2f49186a7..6ab1f0bfdb89 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
@@ -20,31 +20,28 @@ import android.app.Instrumentation
import android.os.Bundle
import android.support.test.launcherhelper.LauncherStrategyFactory
import android.view.Surface
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.exitSplitScreen
-import com.android.server.wm.flicker.helpers.isInSplitScreen
+import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
-import com.android.server.wm.flicker.helpers.openQuickstep
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-abstract class LegacySplitScreenTransition(
- protected val instrumentation: Instrumentation
-) {
- internal val splitScreenApp = SplitScreenHelper.getPrimary(instrumentation)
- internal val secondaryApp = SplitScreenHelper.getSecondary(instrumentation)
- internal val nonResizeableApp = SplitScreenHelper.getNonResizeable(instrumentation)
- internal val LAUNCHER_PACKAGE_NAME = LauncherStrategyFactory.getInstance(instrumentation)
+abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestParameter) {
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ protected val isRotated = testSpec.config.startRotation.isRotated()
+ protected val splitScreenApp = SplitScreenHelper.getPrimary(instrumentation)
+ protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation)
+ protected val nonResizeableApp = SplitScreenHelper.getNonResizeable(instrumentation)
+ protected val LAUNCHER_PACKAGE_NAME = LauncherStrategyFactory.getInstance(instrumentation)
.launcherStrategy.supportedLauncherPackage
- internal val LIVE_WALLPAPER_PACKAGE_NAME =
- "com.breel.wallpapers18.soundviz.wallpaper.variations.SoundVizWallpaperV2"
- internal val LETTERBOX_NAME = "Letterbox"
- internal val TOAST_NAME = "Toast"
- internal val SPLASH_SCREEN_NAME = "Splash Screen"
- internal open val defaultTransitionSetup: FlickerBuilder.(Bundle) -> Unit
+ protected open val transition: FlickerBuilder.(Bundle) -> Unit
get() = { configuration ->
setup {
eachRun {
@@ -57,17 +54,22 @@ abstract class LegacySplitScreenTransition(
}
teardown {
eachRun {
- // TODO(b/175687842) Workaround for exit legacy split screen
- device.openQuickstep(wmHelper)
- if (device.isInSplitScreen()) {
- device.exitSplitScreen()
- }
- device.pressHome()
+ secondaryApp.exit(wmHelper)
+ splitScreenApp.exit(wmHelper)
this.setRotation(Surface.ROTATION_0)
}
}
}
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ transition(this, testSpec.config)
+ }
+ }
+
internal open val cleanSetup: FlickerBuilder.(Bundle) -> Unit
get() = { configuration ->
setup {
@@ -79,37 +81,19 @@ abstract class LegacySplitScreenTransition(
}
teardown {
eachRun {
- // TODO(b/175687842) Workaround for exit legacy split screen
- device.openQuickstep(wmHelper)
- if (device.isInSplitScreen()) {
- device.exitSplitScreen()
- }
+ nonResizeableApp.exit(wmHelper)
+ splitScreenApp.exit(wmHelper)
device.pressHome()
this.setRotation(Surface.ROTATION_0)
}
}
}
- internal open val customRotateSetup: FlickerBuilder.(Bundle) -> Unit
- get() = { configuration ->
- setup {
- eachRun {
- device.wakeUpAndGoToHomeScreen()
- device.openQuickStepAndClearRecentAppsFromOverview(wmHelper)
- secondaryApp.launchViaIntent(wmHelper)
- splitScreenApp.launchViaIntent(wmHelper)
- }
- }
- teardown {
- eachRun {
- // TODO(b/175687842) Workaround for exit legacy split screen
- device.openQuickstep(wmHelper)
- if (device.isInSplitScreen()) {
- device.exitSplitScreen()
- }
- device.pressHome()
- this.setRotation(Surface.ROTATION_0)
- }
- }
- }
+ companion object {
+ internal const val LIVE_WALLPAPER_PACKAGE_NAME =
+ "com.breel.wallpapers18.soundviz.wallpaper.variations.SoundVizWallpaperV2"
+ internal const val LETTERBOX_NAME = "Letterbox"
+ internal const val TOAST_NAME = "Toast"
+ internal const val SPLASH_SCREEN_NAME = "Splash Screen"
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt
index a8de8db719a8..1b4b54a74eab 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt
@@ -19,15 +19,15 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.os.Bundle
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.appWindowBecomesInVisible
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.layerBecomesInvisible
@@ -36,6 +36,7 @@ import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEnt
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -45,61 +46,73 @@ import org.junit.runners.Parameterized
* (Non resizable activity launch via recent overview)
* To run this test: `atest WMShellFlickerTests:NonResizableDismissInLegacySplitScreen`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class NonResizableDismissInLegacySplitScreen(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag("testNonResizableDismissInLegacySplitScreen", configuration)
- }
- repeat { SplitScreenHelper.TEST_REPETITIONS }
- setup {
- eachRun {
- nonResizeableApp.launchViaIntent(wmHelper)
- splitScreenApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- }
- }
- transitions {
- device.reopenAppFromOverview(wmHelper)
- }
- assertions {
- layersTrace {
- layerBecomesVisible(nonResizeableApp.defaultWindowName)
- layerBecomesInvisible(splitScreenApp.defaultWindowName)
- visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME,
- LETTERBOX_NAME, TOAST_NAME,
- splitScreenApp.defaultWindowName,
- nonResizeableApp.defaultWindowName),
- bugId = 178447631
- )
- }
- windowManagerTrace {
- appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
- appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
- visibleWindowsShownMoreThanOneConsecutiveEntry(
- listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME,
- LETTERBOX_NAME, TOAST_NAME,
- splitScreenApp.defaultWindowName,
- nonResizeableApp.defaultWindowName),
- bugId = 178447631
- )
- }
+ testSpec: FlickerTestParameter
+) : LegacySplitScreenTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ cleanSetup(this, configuration)
+ setup {
+ eachRun {
+ nonResizeableApp.launchViaIntent(wmHelper)
+ splitScreenApp.launchViaIntent(wmHelper)
+ device.launchSplitScreen(wmHelper)
}
}
- return FlickerTestRunnerFactory.getInstance().buildTest(
- instrumentation, cleanSetup, testSpec,
+ transitions {
+ device.reopenAppFromOverview(wmHelper)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+
+ @FlakyTest(bugId = 178447631)
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME,
+ LETTERBOX_NAME, TOAST_NAME,
+ splitScreenApp.defaultWindowName,
+ nonResizeableApp.defaultWindowName)
+ )
+
+ @Presubmit
+ @Test
+ fun layerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+
+ @Presubmit
+ @Test
+ fun appWindowBecomesVisible() =
+ testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
+
+ @Presubmit
+ @Test
+ fun appWindowBecomesInVisible() =
+ testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
+
+ @FlakyTest(bugId = 178447631)
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(
+ listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME,
+ LETTERBOX_NAME, TOAST_NAME,
+ splitScreenApp.defaultWindowName,
+ nonResizeableApp.defaultWindowName)
+ )
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0 /* bugId = 178685668 */))
+ supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt
index c82c80237912..2365e3bfd8c3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt
@@ -19,15 +19,15 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.os.Bundle
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.appWindowBecomesInVisible
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.layerBecomesInvisible
import com.android.server.wm.flicker.layerBecomesVisible
@@ -35,6 +35,7 @@ import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEnt
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -47,60 +48,73 @@ import org.junit.runners.Parameterized
@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class NonResizableLaunchInLegacySplitScreen(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag("testNonResizableLaunchInLegacySplitScreen", configuration)
- }
- repeat { SplitScreenHelper.TEST_REPETITIONS }
- setup {
- eachRun {
- splitScreenApp.launchViaIntent(wmHelper)
- device.launchSplitScreen(wmHelper)
- }
- }
- transitions {
- nonResizeableApp.launchViaIntent(wmHelper)
- wmHelper.waitForAppTransitionIdle()
- }
- assertions {
- layersTrace {
- layerBecomesVisible(nonResizeableApp.defaultWindowName)
- layerBecomesInvisible(splitScreenApp.defaultWindowName)
- visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(DOCKED_STACK_DIVIDER,
- LAUNCHER_PACKAGE_NAME,
- LETTERBOX_NAME,
- nonResizeableApp.defaultWindowName,
- splitScreenApp.defaultWindowName),
- bugId = 178447631
- )
- }
- windowManagerTrace {
- appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
- appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
- visibleWindowsShownMoreThanOneConsecutiveEntry(
- listOf(DOCKED_STACK_DIVIDER,
- LAUNCHER_PACKAGE_NAME,
- LETTERBOX_NAME,
- nonResizeableApp.defaultWindowName,
- splitScreenApp.defaultWindowName),
- bugId = 178447631
- )
- }
+ testSpec: FlickerTestParameter
+) : LegacySplitScreenTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ cleanSetup(this, configuration)
+ setup {
+ eachRun {
+ splitScreenApp.launchViaIntent(wmHelper)
+ device.launchSplitScreen(wmHelper)
}
}
- return FlickerTestRunnerFactory.getInstance().buildTest(
- instrumentation, cleanSetup, testSpec,
+ transitions {
+ nonResizeableApp.launchViaIntent(wmHelper)
+ wmHelper.waitForAppTransitionIdle()
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun layerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+
+ @Presubmit
+ @Test
+ fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+
+ @FlakyTest(bugId = 178447631)
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(DOCKED_STACK_DIVIDER,
+ LAUNCHER_PACKAGE_NAME,
+ LETTERBOX_NAME,
+ nonResizeableApp.defaultWindowName,
+ splitScreenApp.defaultWindowName)
+ )
+
+ @Presubmit
+ @Test
+ fun appWindowBecomesVisible() =
+ testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
+
+ @Presubmit
+ @Test
+ fun appWindowBecomesInVisible() =
+ testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
+
+ @FlakyTest(bugId = 178447631)
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(
+ listOf(DOCKED_STACK_DIVIDER,
+ LAUNCHER_PACKAGE_NAME,
+ LETTERBOX_NAME,
+ nonResizeableApp.defaultWindowName,
+ splitScreenApp.defaultWindowName)
+ )
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0 /* bugId = 178685668 */))
+ supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
index 9199c39535ac..b369a3d32e64 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
@@ -19,14 +19,14 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.os.Bundle
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.focusChanges
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.layerBecomesVisible
import com.android.server.wm.flicker.noUncoveredRegions
@@ -34,10 +34,10 @@ import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import com.android.wm.shell.flicker.appPairsDividerBecomesVisible
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -46,54 +46,66 @@ import org.junit.runners.Parameterized
* Test open app to split screen.
* To run this test: `atest WMShellFlickerTests:OpenAppToLegacySplitScreen`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppToLegacySplitScreen(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val wmHelper = WindowManagerStateHelper()
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag("testOpenAppToLegacySplitScreen", configuration)
- }
- repeat { SplitScreenHelper.TEST_REPETITIONS }
- transitions {
- device.launchSplitScreen(wmHelper)
- wmHelper.waitForAppTransitionIdle()
- }
- assertions {
- windowManagerTrace {
- visibleWindowsShownMoreThanOneConsecutiveEntry(
- listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName),
- bugId = 178447631)
- appWindowBecomesVisible(splitScreenApp.getPackage())
- }
+ testSpec: FlickerTestParameter
+) : LegacySplitScreenTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ super.transition(this, configuration)
+ transitions {
+ device.launchSplitScreen(wmHelper)
+ wmHelper.waitForAppTransitionIdle()
+ }
+ }
- layersTrace {
- noUncoveredRegions(configuration.startRotation, enabled = false)
- statusBarLayerIsAlwaysVisible()
- appPairsDividerBecomesVisible()
- layerBecomesVisible(splitScreenApp.getPackage())
- visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName),
- bugId = 178447631)
- }
+ @FlakyTest(bugId = 178447631)
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(
+ listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName)
+ )
- eventLog {
- focusChanges(splitScreenApp.`package`,
- "recents_animation_input_consumer", "NexusLauncherActivity",
- bugId = 151179149)
- }
- }
- }
- return FlickerTestRunnerFactory.getInstance().buildTest(
- instrumentation, defaultTransitionSetup, testSpec,
+ @Presubmit
+ @Test
+ fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(splitScreenApp.getPackage())
+
+ @FlakyTest
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun appPairsDividerBecomesVisible() = testSpec.appPairsDividerBecomesVisible()
+
+ @Presubmit
+ @Test
+ fun layerBecomesVisible() = testSpec.layerBecomesVisible(splitScreenApp.getPackage())
+
+ @FlakyTest(bugId = 178447631)
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName)
+ )
+
+ @FlakyTest(bugId = 151179149)
+ @Test
+ fun focusChanges() = testSpec.focusChanges(splitScreenApp.`package`,
+ "recents_animation_input_consumer", "NexusLauncherActivity")
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
repetitions = SplitScreenHelper.TEST_REPETITIONS,
supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910
)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
index c305bd856f58..ffffa1902976 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
@@ -16,24 +16,21 @@
package com.android.wm.shell.flicker.legacysplitscreen
-import android.platform.test.annotations.Presubmit
import android.graphics.Region
+import android.os.Bundle
import android.util.Rational
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By
import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.focusDoesNotChange
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.helpers.buildTestTag
-import com.android.server.wm.flicker.helpers.exitSplitScreen
-import com.android.server.wm.flicker.helpers.isInSplitScreen
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.resizeSplitScreen
import com.android.server.wm.flicker.helpers.setRotation
@@ -42,7 +39,6 @@ import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
@@ -52,6 +48,7 @@ import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.traces.layers.getVisibleBounds
import com.android.wm.shell.flicker.helpers.SimpleAppHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -62,14 +59,162 @@ import org.junit.runners.Parameterized
*
* Currently it runs only in 0 degrees because of b/156100803
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 159096424)
class ResizeLegacySplitScreen(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
+ testSpec: FlickerTestParameter
+) : LegacySplitScreenTransition(testSpec) {
+ private val testAppTop = SimpleAppHelper(instrumentation)
+ private val testAppBottom = ImeAppHelper(instrumentation)
+
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(configuration.startRotation)
+ this.launcherStrategy.clearRecentAppsFromOverview()
+ testAppBottom.launchViaIntent(wmHelper)
+ device.pressHome()
+ testAppTop.launchViaIntent(wmHelper)
+ device.waitForIdle()
+ device.launchSplitScreen(wmHelper)
+ val snapshot =
+ device.findObject(By.res(device.launcherPackageName, "snapshot"))
+ snapshot.click()
+ testAppBottom.openIME(device)
+ device.pressBack()
+ device.resizeSplitScreen(startRatio)
+ }
+ }
+ teardown {
+ eachRun {
+ testAppTop.exit(wmHelper)
+ testAppBottom.exit(wmHelper)
+ }
+ }
+ transitions {
+ device.resizeSplitScreen(stopRatio)
+ }
+ }
+
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ @FlakyTest(bugId = 156223549)
+ @Test
+ fun topAppWindowIsAlwaysVisible() {
+ testSpec.assertWm {
+ this.showsAppWindow(sSimpleActivity)
+ }
+ }
+
+ @FlakyTest(bugId = 156223549)
+ @Test
+ fun bottomAppWindowIsAlwaysVisible() {
+ testSpec.assertWm {
+ this.showsAppWindow(sImeActivity)
+ }
+ }
+
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.endRotation)
+
+ @Test
+ fun navBarLayerRotatesAndScales() =
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.endRotation)
+
+ @Test
+ fun statusBarLayerRotatesScales() =
+ testSpec.statusBarLayerRotatesScales(testSpec.config.endRotation)
+
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @Test
+ fun topAppLayerIsAlwaysVisible() {
+ testSpec.assertLayers {
+ this.showsLayer(sSimpleActivity)
+ }
+ }
+
+ @Test
+ fun bottomAppLayerIsAlwaysVisible() {
+ testSpec.assertLayers {
+ this.showsLayer(sImeActivity)
+ }
+ }
+
+ @Test
+ fun dividerLayerIsAlwaysVisible() {
+ testSpec.assertLayers {
+ this.showsLayer(DOCKED_STACK_DIVIDER)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ fun appsStartingBounds() {
+ testSpec.assertLayersStart {
+ val displayBounds = WindowUtils.displayBounds
+ val dividerBounds =
+ entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds
+
+ val topAppBounds = Region(0, 0, dividerBounds.right,
+ dividerBounds.top + WindowUtils.dockedStackDividerInset)
+ val bottomAppBounds = Region(0,
+ dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
+ displayBounds.right,
+ displayBounds.bottom - WindowUtils.navigationBarHeight)
+ this.hasVisibleRegion("SimpleActivity", topAppBounds)
+ .hasVisibleRegion("ImeActivity", bottomAppBounds)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ fun appsEndingBounds() {
+ testSpec.assertLayersStart {
+ val displayBounds = WindowUtils.displayBounds
+ val dividerBounds =
+ entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds
+
+ val topAppBounds = Region(0, 0, dividerBounds.right,
+ dividerBounds.top + WindowUtils.dockedStackDividerInset)
+ val bottomAppBounds = Region(0,
+ dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
+ displayBounds.right,
+ displayBounds.bottom - WindowUtils.navigationBarHeight)
+
+ this.hasVisibleRegion(sSimpleActivity, topAppBounds)
+ .hasVisibleRegion(sImeActivity, bottomAppBounds)
+ }
+ }
+
+ @Test
+ fun focusDoesNotChange() {
+ testSpec.assertEventLog {
+ focusDoesNotChange()
+ }
+ }
+
companion object {
private const val sSimpleActivity = "SimpleActivity"
private const val sImeActivity = "ImeActivity"
@@ -78,126 +223,14 @@ class ResizeLegacySplitScreen(
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val testAppTop = SimpleAppHelper(instrumentation)
- val testAppBottom = ImeAppHelper(instrumentation)
-
- return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation,
- supportedRotations = listOf(Surface.ROTATION_0)) { configuration ->
- withTestName {
- val description = (startRatio.toString().replace("/", "-") + "_to_" +
- stopRatio.toString().replace("/", "-"))
- buildTestTag("resizeSplitScreen", configuration, description)
- }
- repeat { configuration.repetitions }
- setup {
- eachRun {
- device.wakeUpAndGoToHomeScreen()
- this.setRotation(configuration.startRotation)
- this.launcherStrategy.clearRecentAppsFromOverview()
- testAppBottom.launchViaIntent(wmHelper)
- device.pressHome()
- testAppTop.launchViaIntent(wmHelper)
- device.waitForIdle()
- device.launchSplitScreen(wmHelper)
- val snapshot =
- device.findObject(By.res(device.launcherPackageName, "snapshot"))
- snapshot.click()
- testAppBottom.openIME(device)
- device.pressBack()
- device.resizeSplitScreen(startRatio)
- }
- }
- teardown {
- eachRun {
- if (device.isInSplitScreen()) {
- device.exitSplitScreen()
- }
- device.pressHome()
- testAppTop.exit()
- testAppBottom.exit()
- }
- test {
- if (device.isInSplitScreen()) {
- device.exitSplitScreen()
- }
- }
- }
- transitions {
- device.resizeSplitScreen(stopRatio)
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- all("topAppWindowIsAlwaysVisible", bugId = 156223549) {
- this.showsAppWindow(sSimpleActivity)
- }
-
- all("bottomAppWindowIsAlwaysVisible", bugId = 156223549) {
- this.showsAppWindow(sImeActivity)
- }
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(configuration.endRotation)
- navBarLayerRotatesAndScales(configuration.endRotation)
- statusBarLayerRotatesScales(configuration.endRotation)
- visibleLayersShownMoreThanOneConsecutiveEntry()
-
- all("topAppLayerIsAlwaysVisible") {
- this.showsLayer(sSimpleActivity)
- }
-
- all("bottomAppLayerIsAlwaysVisible") {
- this.showsLayer(sImeActivity)
- }
-
- all("dividerLayerIsAlwaysVisible") {
- this.showsLayer(DOCKED_STACK_DIVIDER)
- }
-
- start("appsStartingBounds", enabled = false) {
- val displayBounds = WindowUtils.displayBounds
- val dividerBounds =
- entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds
-
- val topAppBounds = Region(0, 0, dividerBounds.right,
- dividerBounds.top + WindowUtils.dockedStackDividerInset)
- val bottomAppBounds = Region(0,
- dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
- displayBounds.right,
- displayBounds.bottom - WindowUtils.navigationBarHeight)
- this.hasVisibleRegion("SimpleActivity", topAppBounds)
- .hasVisibleRegion("ImeActivity", bottomAppBounds)
- }
-
- end("appsEndingBounds", enabled = false) {
- val displayBounds = WindowUtils.displayBounds
- val dividerBounds =
- entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds
-
- val topAppBounds = Region(0, 0, dividerBounds.right,
- dividerBounds.top + WindowUtils.dockedStackDividerInset)
- val bottomAppBounds = Region(0,
- dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
- displayBounds.right,
- displayBounds.bottom - WindowUtils.navigationBarHeight)
-
- this.hasVisibleRegion(sSimpleActivity, topAppBounds)
- .hasVisibleRegion(sImeActivity, bottomAppBounds)
- }
- }
-
- eventLog {
- focusDoesNotChange()
- }
- }
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
+ .map {
+ val description = (startRatio.toString().replace("/", "-") + "_to_" +
+ stopRatio.toString().replace("/", "-"))
+ val newName = "${FlickerTestParameter.defaultName(it.config)}_$description"
+ FlickerTestParameter(it.config, name = newName)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
index 40bdaf3df5e8..c538008aa179 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
@@ -19,14 +19,14 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.os.Bundle
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
@@ -38,6 +38,7 @@ import com.android.wm.shell.flicker.dockedStackDividerIsVisible
import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -46,50 +47,64 @@ import org.junit.runners.Parameterized
* Test dock activity to primary split screen and rotate
* To run this test: `atest WMShellFlickerTests:RotateOneLaunchedAppAndEnterSplitScreen`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class RotateOneLaunchedAppAndEnterSplitScreen(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) {
+ testSpec: FlickerTestParameter
+) : LegacySplitScreenRotateTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ super.transition(this, configuration)
+ transitions {
+ device.launchSplitScreen(wmHelper)
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+
+ @FlakyTest(bugId = 175687842)
+ @Test
+ fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible()
+
+ @FlakyTest(bugId = 175687842)
+ @Test
+ fun dockedStackPrimaryBoundsIsVisible() =
+ testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation,
+ splitScreenApp.defaultWindowName)
+
+ @FlakyTest(bugId = 169271943)
+ @Test
+ fun navBarLayerRotatesAndScales() =
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
+ testSpec.config.endRotation)
+
+ @FlakyTest(bugId = 169271943)
+ @Test
+ fun statusBarLayerRotatesScales() =
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
+ testSpec.config.endRotation)
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun appWindowBecomesVisible() =
+ testSpec.appWindowBecomesVisible(splitScreenApp.defaultWindowName)
+
+ companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag("testRotateOneLaunchedAppAndEnterSplitScreen", configuration)
- }
- repeat { SplitScreenHelper.TEST_REPETITIONS }
- transitions {
- device.launchSplitScreen(wmHelper)
- this.setRotation(configuration.startRotation)
- }
- assertions {
- layersTrace {
- dockedStackDividerIsVisible(bugId = 175687842)
- dockedStackPrimaryBoundsIsVisible(
- configuration.startRotation,
- splitScreenApp.defaultWindowName, bugId = 175687842)
- navBarLayerRotatesAndScales(
- configuration.startRotation,
- configuration.endRotation, bugId = 169271943)
- statusBarLayerRotatesScales(
- configuration.startRotation,
- configuration.endRotation, bugId = 169271943)
- }
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- appWindowBecomesVisible(splitScreenApp.defaultWindowName)
- }
- }
- }
- return FlickerTestRunnerFactory.getInstance().buildTest(
- instrumentation, customRotateSetup, testSpec,
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0 /* bugId = 178685668 */))
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = SplitScreenHelper.TEST_REPETITIONS,
+ supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
index ae2c2d8f1bf2..c1162560119c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
@@ -19,14 +19,14 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.os.Bundle
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
@@ -38,6 +38,7 @@ import com.android.wm.shell.flicker.dockedStackDividerIsVisible
import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -46,50 +47,61 @@ import org.junit.runners.Parameterized
* Rotate
* To run this test: `atest WMShellFlickerTests:RotateOneLaunchedAppInSplitScreenMode`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class RotateOneLaunchedAppInSplitScreenMode(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) {
+ testSpec: FlickerTestParameter
+) : LegacySplitScreenRotateTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ super.transition(this, configuration)
+ transitions {
+ this.setRotation(testSpec.config.startRotation)
+ device.launchSplitScreen(wmHelper)
+ }
+ }
+
+ @FlakyTest(bugId = 175687842)
+ @Test
+ fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible()
+
+ @FlakyTest(bugId = 175687842)
+ @Test
+ fun dockedStackPrimaryBoundsIsVisible() = testSpec.dockedStackPrimaryBoundsIsVisible(
+ testSpec.config.startRotation, splitScreenApp.defaultWindowName)
+
+ @FlakyTest(bugId = 169271943)
+ @Test
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales(
+ testSpec.config.startRotation, testSpec.config.endRotation)
+
+ @FlakyTest(bugId = 169271943)
+ @Test
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(
+ testSpec.config.startRotation, testSpec.config.endRotation)
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun appWindowBecomesVisible() =
+ testSpec.appWindowBecomesVisible(splitScreenApp.defaultWindowName)
+
+ companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag("testRotateOneLaunchedAppInSplitScreenMode", configuration)
- }
- repeat { SplitScreenHelper.TEST_REPETITIONS }
- transitions {
- this.setRotation(configuration.startRotation)
- device.launchSplitScreen(wmHelper)
- }
- assertions {
- layersTrace {
- dockedStackDividerIsVisible(bugId = 175687842)
- dockedStackPrimaryBoundsIsVisible(
- configuration.startRotation,
- splitScreenApp.defaultWindowName, bugId = 175687842)
- navBarLayerRotatesAndScales(
- configuration.startRotation,
- configuration.endRotation, bugId = 169271943)
- statusBarLayerRotatesScales(
- configuration.startRotation,
- configuration.endRotation, bugId = 169271943)
- }
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- appWindowBecomesVisible(splitScreenApp.defaultWindowName)
- }
- }
- }
- return FlickerTestRunnerFactory.getInstance().buildTest(
- instrumentation, customRotateSetup, testSpec,
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0 /* bugId = 178685668 */))
+ supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
index aa9ac8f9782f..273925c0361c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
@@ -19,14 +19,14 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.os.Bundle
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
@@ -40,6 +40,7 @@ import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -48,54 +49,69 @@ import org.junit.runners.Parameterized
* Test open app to split screen.
* To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppAndEnterSplitScreen`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class RotateTwoLaunchedAppAndEnterSplitScreen(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) {
+ testSpec: FlickerTestParameter
+) : LegacySplitScreenRotateTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ super.transition(this, configuration)
+ transitions {
+ this.setRotation(testSpec.config.startRotation)
+ device.launchSplitScreen(wmHelper)
+ device.reopenAppFromOverview(wmHelper)
+ }
+ }
+
+ @FlakyTest(bugId = 175687842)
+ @Test
+ fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible()
+
+ @FlakyTest(bugId = 175687842)
+ @Test
+ fun dockedStackPrimaryBoundsIsVisible() =
+ testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation,
+ splitScreenApp.defaultWindowName)
+
+ @FlakyTest(bugId = 175687842)
+ @Test
+ fun dockedStackSecondaryBoundsIsVisible() =
+ testSpec.dockedStackSecondaryBoundsIsVisible(testSpec.config.startRotation,
+ secondaryApp.defaultWindowName)
+
+ @FlakyTest(bugId = 169271943)
+ @Test
+ fun navBarLayerRotatesAndScales() =
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
+ testSpec.config.endRotation)
+
+ @FlakyTest(bugId = 169271943)
+ @Test
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(
+ testSpec.config.startRotation, testSpec.config.endRotation)
+
+ @Presubmit
+ @Test
+ fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp.defaultWindowName)
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag("testRotateTwoLaunchedAppAndEnterSplitScreen", configuration)
- }
- repeat { SplitScreenHelper.TEST_REPETITIONS }
- transitions {
- this.setRotation(configuration.startRotation)
- device.launchSplitScreen(wmHelper)
- device.reopenAppFromOverview(wmHelper)
- }
- assertions {
- layersTrace {
- dockedStackDividerIsVisible(bugId = 175687842)
- dockedStackPrimaryBoundsIsVisible(
- configuration.startRotation,
- splitScreenApp.defaultWindowName, 175687842)
- dockedStackSecondaryBoundsIsVisible(
- configuration.startRotation,
- secondaryApp.defaultWindowName, bugId = 175687842)
- navBarLayerRotatesAndScales(
- configuration.startRotation,
- configuration.endRotation, bugId = 169271943)
- statusBarLayerRotatesScales(
- configuration.startRotation,
- configuration.endRotation, bugId = 169271943)
- }
- windowManagerTrace {
- appWindowBecomesVisible(secondaryApp.defaultWindowName)
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- }
- }
- }
- return FlickerTestRunnerFactory.getInstance().buildTest(
- instrumentation, customRotateSetup, testSpec,
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0 /* bugId = 178685668 */))
+ supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
index 0e864dbbb75d..c7188dc227e7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
@@ -19,14 +19,14 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.os.Bundle
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
@@ -40,6 +40,7 @@ import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -48,59 +49,76 @@ import org.junit.runners.Parameterized
* Test open app to split screen.
* To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppInSplitScreenMode`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class RotateTwoLaunchedAppInSplitScreenMode(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- buildTestTag("testRotateTwoLaunchedAppInSplitScreenMode", configuration)
- }
- repeat { SplitScreenHelper.TEST_REPETITIONS }
- setup {
- eachRun {
- device.launchSplitScreen(wmHelper)
- device.reopenAppFromOverview(wmHelper)
- this.setRotation(configuration.startRotation)
- }
- }
- transitions {
- this.setRotation(configuration.startRotation)
- }
- assertions {
- layersTrace {
- dockedStackDividerIsVisible(bugId = 175687842)
- dockedStackPrimaryBoundsIsVisible(
- configuration.startRotation,
- splitScreenApp.defaultWindowName, bugId = 175687842)
- dockedStackSecondaryBoundsIsVisible(
- configuration.startRotation,
- secondaryApp.defaultWindowName, bugId = 175687842)
- navBarLayerRotatesAndScales(
- configuration.startRotation,
- configuration.endRotation, bugId = 169271943)
- statusBarLayerRotatesScales(
- configuration.startRotation,
- configuration.endRotation, bugId = 169271943)
- }
- windowManagerTrace {
- appWindowBecomesVisible(secondaryApp.defaultWindowName)
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- }
+ testSpec: FlickerTestParameter
+) : LegacySplitScreenRotateTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ super.transition(this, configuration)
+ setup {
+ eachRun {
+ device.launchSplitScreen(wmHelper)
+ device.reopenAppFromOverview(wmHelper)
+ this.setRotation(testSpec.config.startRotation)
}
}
- return FlickerTestRunnerFactory.getInstance().buildTest(
- instrumentation, customRotateSetup, testSpec,
+ transitions {
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+
+ @FlakyTest(bugId = 175687842)
+ @Test
+ fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible()
+
+ @FlakyTest(bugId = 175687842)
+ @Test
+ fun dockedStackPrimaryBoundsIsVisible() =
+ testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation,
+ splitScreenApp.defaultWindowName)
+
+ @FlakyTest(bugId = 175687842)
+ @Test
+ fun dockedStackSecondaryBoundsIsVisible() =
+ testSpec.dockedStackSecondaryBoundsIsVisible(testSpec.config.startRotation,
+ secondaryApp.defaultWindowName)
+
+ @FlakyTest(bugId = 169271943)
+ @Test
+ fun navBarLayerRotatesAndScales() =
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
+ testSpec.config.endRotation)
+
+ @FlakyTest(bugId = 169271943)
+ @Test
+ fun statusBarLayerRotatesScales() =
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
+ testSpec.config.endRotation)
+
+ @Presubmit
+ @Test
+ fun appWindowBecomesVisible() =
+ testSpec.appWindowBecomesVisible(secondaryApp.defaultWindowName)
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0 /* bugId = 178685668 */))
+ supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt
deleted file mode 100644
index bc42d5ed04ce..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt
+++ /dev/null
@@ -1,33 +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.flicker.pip
-
-import android.os.SystemClock
-import com.android.wm.shell.flicker.NonRotationTestBase
-
-abstract class AppTestBase(
- rotationName: String,
- rotation: Int
-) : NonRotationTestBase(rotationName, rotation) {
- companion object {
- fun waitForAnimationComplete() {
- // TODO: UiDevice doesn't have reliable way to wait for the completion of animation.
- // Consider to introduce WindowManagerStateHelper to access Activity state.
- SystemClock.sleep(1000)
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
index d56ed02972fb..ca48eaa45840 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
@@ -16,11 +16,14 @@
package com.android.wm.shell.flicker.pip
+import android.os.Bundle
+import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.wm.shell.flicker.helpers.FixedAppHelper
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
@@ -29,6 +32,7 @@ import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,64 +43,96 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class EnterExitPipTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<Array<Any>> {
- val testApp = FixedAppHelper(instrumentation)
- val testSpec = getTransition(eachRun = true) { configuration ->
- setup {
- eachRun {
- testApp.launchViaIntent(wmHelper)
- }
- }
- transitions {
- // This will bring PipApp to fullscreen
- pipApp.launchViaIntent(wmHelper)
- }
- assertions {
- val displayBounds = WindowUtils.getDisplayBounds(configuration.startRotation)
- presubmit {
- windowManagerTrace {
- all("pipApp must remain inside visible bounds") {
- coversAtMostRegion(pipApp.defaultWindowName, displayBounds)
- }
- all("Initially shows both app windows then pipApp hides testApp") {
- showsAppWindow(testApp.defaultWindowName)
- .showsAppWindowOnTop(pipApp.defaultWindowName)
- .then()
- .hidesAppWindow(testApp.defaultWindowName)
- }
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- }
- layersTrace {
- all("Initially shows both app layers then pipApp hides testApp") {
- showsLayer(testApp.defaultWindowName)
- .showsLayer(pipApp.defaultWindowName)
- .then()
- .hidesLayer(testApp.defaultWindowName)
- }
- start("testApp covers the fullscreen, pipApp remains inside display") {
- hasVisibleRegion(testApp.defaultWindowName, displayBounds)
- coversAtMostRegion(displayBounds, pipApp.defaultWindowName)
- }
- end("pipApp covers the fullscreen") {
- hasVisibleRegion(pipApp.defaultWindowName, displayBounds)
- }
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- }
- }
+ testSpec: FlickerTestParameter
+) : PipTransition(testSpec) {
+ private val testApp = FixedAppHelper(instrumentation)
+ private val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = buildTransition(eachRun = true) {
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
}
}
- return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation,
- testSpec, supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 5)
+ transitions {
+ // This will bring PipApp to fullscreen
+ pipApp.launchViaIntent(wmHelper)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun pipAppRemainInsideVisibleBounds() {
+ testSpec.assertWm {
+ coversAtMostRegion(pipApp.defaultWindowName, displayBounds)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun showBothAppWindowsThenHidePip() {
+ testSpec.assertWm {
+ showsAppWindow(testApp.defaultWindowName)
+ .showsAppWindowOnTop(pipApp.defaultWindowName)
+ .then()
+ .hidesAppWindow(testApp.defaultWindowName)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun showBothAppLayersThenHidePip() {
+ testSpec.assertLayers {
+ showsLayer(testApp.defaultWindowName)
+ .showsLayer(pipApp.defaultWindowName)
+ .then()
+ .hidesLayer(testApp.defaultWindowName)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun testAppCoversFullScreenWithPipOnDisplay() {
+ testSpec.assertLayersStart {
+ hasVisibleRegion(testApp.defaultWindowName, displayBounds)
+ coversAtMostRegion(displayBounds, pipApp.defaultWindowName)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun pipAppCoversFullScreen() {
+ testSpec.assertLayersEnd {
+ hasVisibleRegion(pipApp.defaultWindowName, displayBounds)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+ supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index ff31ba7d2c01..e1fbc16e8ce2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -16,11 +16,15 @@
package com.android.wm.shell.flicker.pip
+import android.os.Bundle
+import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
@@ -30,6 +34,7 @@ import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.startRotation
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -40,58 +45,71 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterPipTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<Array<Any>> {
- val testSpec = getTransition(eachRun = true,
- stringExtras = emptyMap()) { configuration ->
- transitions {
- pipApp.clickEnterPipButton()
- pipApp.expandPipWindow(wmHelper)
- }
- assertions {
- presubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
+class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = buildTransition(eachRun = true, stringExtras = emptyMap()) {
+ transitions {
+ pipApp.clickEnterPipButton()
+ pipApp.expandPipWindow(wmHelper)
+ }
+ }
- all("pipWindowBecomesVisible") {
- this.showsAppWindow(pipApp.defaultWindowName)
- }
- }
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
- layersTrace {
- statusBarLayerIsAlwaysVisible()
- statusBarLayerRotatesScales(configuration.startRotation,
- Surface.ROTATION_0)
- }
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- layersTrace {
- all("pipLayerBecomesVisible") {
- this.showsLayer(pipApp.launcherName)
- }
- }
- }
+ @Presubmit
+ @Test
+ fun pipWindowBecomesVisible() {
+ testSpec.assertWm {
+ this.showsAppWindow(pipApp.defaultWindowName)
+ }
+ }
- flaky {
- layersTrace {
- navBarLayerIsAlwaysVisible(bugId = 140855415)
- noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0)
- navBarLayerRotatesAndScales(configuration.startRotation,
- Surface.ROTATION_0, bugId = 140855415)
- }
- }
- }
- }
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() =
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
- return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation,
- testSpec, supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 5)
+ @Presubmit
+ @Test
+ fun pipLayerBecomesVisible() {
+ testSpec.assertLayers {
+ this.showsLayer(pipApp.launcherName)
+ }
+ }
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun navBarLayerRotatesAndScales() =
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun noUncoveredRegions() =
+ testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
+ repetitions = 5)
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index eaaa2f6390be..215b97bfeb83 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -16,22 +16,27 @@
package com.android.wm.shell.flicker.pip
+import android.os.Bundle
+import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.wm.shell.flicker.helpers.FixedAppHelper
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.pip.PipTransitionBase.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
-import com.android.wm.shell.flicker.pip.PipTransitionBase.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT
+import com.android.wm.shell.flicker.helpers.FixedAppHelper
+import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
+import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT
import com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_ENTER_PIP
import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -42,82 +47,108 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class EnterPipToOtherOrientationTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) {
- private val testApp = FixedAppHelper(instrumentation)
+ testSpec: FlickerTestParameter
+) : PipTransition(testSpec) {
+ private val testApp = FixedAppHelper(instrumentation)
+ private val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90)
+ private val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0)
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation,
- supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 5) { configuration ->
- setupAndTeardown(this, configuration)
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ setupAndTeardown(this, configuration)
- setup {
- eachRun {
- // Launch a portrait only app on the fullscreen stack
- testApp.launchViaIntent(wmHelper, stringExtras = mapOf(
- EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString()))
- // Launch the PiP activity fixed as landscape
- pipApp.launchViaIntent(wmHelper, stringExtras = mapOf(
- EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString()))
- }
+ setup {
+ eachRun {
+ // Launch a portrait only app on the fullscreen stack
+ testApp.launchViaIntent(wmHelper, stringExtras = mapOf(
+ EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString()))
+ // Launch the PiP activity fixed as landscape
+ pipApp.launchViaIntent(wmHelper, stringExtras = mapOf(
+ EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString()))
}
- teardown {
- eachRun {
- pipApp.exit()
- testApp.exit()
- }
- }
- transitions {
- // Enter PiP, and assert that the PiP is within bounds now that the device is back
- // in portrait
- broadcastActionTrigger.doAction(ACTION_ENTER_PIP)
- wmHelper.waitPipWindowShown()
- wmHelper.waitForAppTransitionIdle()
+ }
+ teardown {
+ eachRun {
+ pipApp.exit(wmHelper)
+ testApp.exit(wmHelper)
}
- assertions {
- val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90)
- val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0)
+ }
+ transitions {
+ // Enter PiP, and assert that the PiP is within bounds now that the device is back
+ // in portrait
+ broadcastActionTrigger.doAction(ACTION_ENTER_PIP)
+ wmHelper.waitPipWindowShown()
+ wmHelper.waitForAppTransitionIdle()
+ }
+ }
- presubmit {
- windowManagerTrace {
- all("pipApp window is always on top") {
- showsAppWindowOnTop(pipApp.defaultWindowName)
- }
- start("pipApp window hides testApp") {
- isInvisible(testApp.defaultWindowName)
- }
- end("testApp windows is shown") {
- isVisible(testApp.defaultWindowName)
- }
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- }
+ @Presubmit
+ @Test
+ fun pipAppWindowIsAlwaysOnTop() {
+ testSpec.assertWm {
+ showsAppWindowOnTop(pipApp.defaultWindowName)
+ }
+ }
- layersTrace {
- start("pipApp layer hides testApp") {
- hasVisibleRegion(pipApp.defaultWindowName, startingBounds)
- isInvisible(testApp.defaultWindowName)
- }
- }
- }
+ @Presubmit
+ @Test
+ fun pipAppHidesTestApp() {
+ testSpec.assertWmStart {
+ isInvisible(testApp.defaultWindowName)
+ }
+ }
- flaky {
- layersTrace {
- end("testApp layer covers fullscreen") {
- hasVisibleRegion(testApp.defaultWindowName, endingBounds)
- }
- navBarLayerIsAlwaysVisible(bugId = 140855415)
- statusBarLayerIsAlwaysVisible(bugId = 140855415)
- }
- }
- }
- }
+ @Presubmit
+ @Test
+ fun testAppWindowIsVisible() {
+ testSpec.assertWmEnd {
+ isVisible(testApp.defaultWindowName)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun pipAppLayerHidesTestApp() {
+ testSpec.assertLayersStart {
+ hasVisibleRegion(pipApp.defaultWindowName, startingBounds)
+ isInvisible(testApp.defaultWindowName)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ fun testAppLayerCoversFullScreen() {
+ testSpec.assertLayersEnd {
+ hasVisibleRegion(testApp.defaultWindowName, endingBounds)
+ }
+ }
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
+ repetitions = 5)
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index f054e6412080..f3b9ea1455ca 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -16,17 +16,21 @@
package com.android.wm.shell.flicker.pip
+import android.os.Bundle
+import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.startRotation
import com.android.wm.shell.flicker.IME_WINDOW_NAME
import com.android.wm.shell.flicker.helpers.ImeAppHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -37,58 +41,67 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class PipKeyboardTest(testSpec: FlickerTestRunnerFactory.TestSpec) : FlickerTestRunner(testSpec) {
- companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) {
- private const val TAG_IME_VISIBLE = "imeIsVisible"
+class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+ private val imeApp = ImeAppHelper(instrumentation)
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val imeApp = ImeAppHelper(instrumentation)
- val testSpec = getTransition(eachRun = false) { configuration ->
- setup {
- test {
- imeApp.launchViaIntent(wmHelper)
- setRotation(configuration.startRotation)
- }
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = buildTransition(eachRun = false) { configuration ->
+ setup {
+ test {
+ imeApp.launchViaIntent(wmHelper)
+ setRotation(configuration.startRotation)
}
- teardown {
- test {
- imeApp.exit()
- setRotation(Surface.ROTATION_0)
- }
+ }
+ teardown {
+ test {
+ imeApp.exit(wmHelper)
+ setRotation(Surface.ROTATION_0)
}
- transitions {
- // open the soft keyboard
- imeApp.openIME(wmHelper)
- createTag(TAG_IME_VISIBLE)
+ }
+ transitions {
+ // open the soft keyboard
+ imeApp.openIME(wmHelper)
+ createTag(TAG_IME_VISIBLE)
- // then close it again
- imeApp.closeIME(wmHelper)
- }
- assertions {
- presubmit {
- windowManagerTrace {
- // Ensure the pip window remains visible throughout
- // any keyboard interactions
- all("pipInVisibleBounds") {
- val displayBounds = WindowUtils.getDisplayBounds(
- configuration.startRotation)
- coversAtMostRegion(pipApp.defaultWindowName, displayBounds)
- }
- // Ensure that the pip window does not obscure the keyboard
- tag(TAG_IME_VISIBLE) {
- isAboveWindow(IME_WINDOW_NAME, pipApp.defaultWindowName)
- }
- }
- }
- }
+ // then close it again
+ imeApp.closeIME(wmHelper)
}
+ }
+
+ /**
+ * Ensure the pip window remains visible throughout any keyboard interactions
+ */
+ @Presubmit
+ @Test
+ fun pipInVisibleBounds() {
+ testSpec.assertWm {
+ val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ coversAtMostRegion(pipApp.defaultWindowName, displayBounds)
+ }
+ }
+
+ /**
+ * Ensure that the pip window does not obscure the keyboard
+ */
+ @Presubmit
+ @Test
+ fun pipIsAboveAppWindow() {
+ testSpec.assertWmTag(TAG_IME_VISIBLE) {
+ isAboveWindow(IME_WINDOW_NAME, pipApp.defaultWindowName)
+ }
+ }
- return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation,
- testSpec, supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 5)
+ companion object {
+ private const val TAG_IME_VISIBLE = "imeIsVisible"
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
+ repetitions = 5)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
index 5a1e5a1fe7c5..daf381ee9ddb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
@@ -16,21 +16,25 @@
package com.android.wm.shell.flicker.pip
+import android.os.Bundle
+import android.platform.test.annotations.Postsubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.dsl.runFlicker
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.helpers.exitSplitScreen
-import com.android.server.wm.flicker.helpers.isInSplitScreen
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.helpers.ImeAppHelper
import com.android.wm.shell.flicker.helpers.FixedAppHelper
-import com.android.wm.shell.flicker.helpers.PipAppHelper
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.removeAllTasksButHome
import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
@@ -46,83 +50,103 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 161435597)
-class PipLegacySplitScreenTest(
- rotationName: String,
- rotation: Int
-) : AppTestBase(rotationName, rotation) {
- private val pipApp = PipAppHelper(instrumentation)
+class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
private val imeApp = ImeAppHelper(instrumentation)
private val testApp = FixedAppHelper(instrumentation)
+ private val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
- @Test
- fun testShowsPipLaunchingToSplitScreen() {
- runFlicker(instrumentation) {
- withTestName { "testShowsPipLaunchingToSplitScreen" }
- repeat { TEST_REPETITIONS }
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
setup {
test {
removeAllTasksButHome()
device.wakeUpAndGoToHomeScreen()
- pipApp.launchViaIntent(stringExtras = mapOf(EXTRA_ENTER_PIP to "true"))
- waitForAnimationComplete()
+ pipApp.launchViaIntent(stringExtras = mapOf(EXTRA_ENTER_PIP to "true"),
+ wmHelper = wmHelper)
}
}
transitions {
- testApp.launchViaIntent()
+ testApp.launchViaIntent(wmHelper)
device.launchSplitScreen(wmHelper)
- imeApp.launchViaIntent()
- waitForAnimationComplete()
+ imeApp.launchViaIntent(wmHelper)
}
teardown {
eachRun {
- imeApp.exit()
- if (device.isInSplitScreen()) {
- device.exitSplitScreen()
- }
- testApp.exit()
+ imeApp.exit(wmHelper)
+ testApp.exit(wmHelper)
}
test {
removeAllTasksButHome()
}
}
- assertions {
- val displayBounds = WindowUtils.getDisplayBounds(rotation)
- windowManagerTrace {
- all("PIP window must remain inside visible bounds") {
- coversAtMostRegion(pipApp.defaultWindowName, displayBounds)
- }
- end("Both app windows should be visible") {
- isVisible(testApp.defaultWindowName)
- isVisible(imeApp.defaultWindowName)
- noWindowsOverlap(setOf(testApp.defaultWindowName, imeApp.defaultWindowName))
- }
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- }
- layersTrace {
- all("PIP layer must remain inside visible bounds") {
- coversAtMostRegion(displayBounds, pipApp.defaultWindowName)
- }
- end("Both app layers should be visible") {
- coversAtMostRegion(displayBounds, testApp.defaultWindowName)
- coversAtMostRegion(displayBounds, imeApp.defaultWindowName)
- }
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- }
- }
+ }
+
+ @Postsubmit
+ @Test
+ fun pipWindowInsideDisplayBounds() {
+ testSpec.assertWm {
+ coversAtMostRegion(pipApp.defaultWindowName, displayBounds)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun bothAppWindowsVisible() {
+ testSpec.assertWmEnd {
+ isVisible(testApp.defaultWindowName)
+ isVisible(imeApp.defaultWindowName)
+ noWindowsOverlap(setOf(testApp.defaultWindowName, imeApp.defaultWindowName))
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun pipLayerInsideDisplayBounds() {
+ testSpec.assertLayers {
+ coversAtMostRegion(displayBounds, pipApp.defaultWindowName)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun bothAppLayersVisible() {
+ testSpec.assertLayersEnd {
+ coversAtMostRegion(displayBounds, testApp.defaultWindowName)
+ coversAtMostRegion(displayBounds, imeApp.defaultWindowName)
}
}
+ @Postsubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
companion object {
const val TEST_REPETITIONS = 2
+
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val supportedRotations = intArrayOf(Surface.ROTATION_0)
- return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+ supportedRotations = listOf(Surface.ROTATION_0),
+ repetitions = TEST_REPETITIONS
+ )
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index ade65ac8aa63..43c12acef9e8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -16,11 +16,15 @@
package com.android.wm.shell.flicker.pip
+import android.os.Bundle
+import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.setRotation
@@ -34,6 +38,7 @@ import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -44,73 +49,91 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class PipRotationTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val fixedApp = FixedAppHelper(instrumentation)
- val testSpec = getTransition(eachRun = false) { configuration ->
- setup {
- test {
- fixedApp.launchViaIntent(wmHelper)
- }
- eachRun {
- setRotation(configuration.startRotation)
- }
+class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+ private val fixedApp = FixedAppHelper(instrumentation)
+ private val startingBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ private val endingBounds = WindowUtils.getDisplayBounds(testSpec.config.endRotation)
+
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = buildTransition(eachRun = false) { configuration ->
+ setup {
+ test {
+ fixedApp.launchViaIntent(wmHelper)
}
- transitions {
- setRotation(configuration.endRotation)
+ eachRun {
+ setRotation(configuration.startRotation)
}
- teardown {
- eachRun {
- setRotation(Surface.ROTATION_0)
- }
+ }
+ transitions {
+ setRotation(configuration.endRotation)
+ }
+ teardown {
+ eachRun {
+ setRotation(Surface.ROTATION_0)
}
- assertions {
- val startingBounds = WindowUtils.getDisplayBounds(configuration.startRotation)
- val endingBounds = WindowUtils.getDisplayBounds(configuration.endRotation)
+ }
+ }
- presubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- }
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
- layersTrace {
- noUncoveredRegions(configuration.startRotation,
- configuration.endRotation, allStates = false)
- }
- }
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- flaky {
- layersTrace {
- navBarLayerIsAlwaysVisible(bugId = 140855415)
- statusBarLayerIsAlwaysVisible(bugId = 140855415)
- navBarLayerRotatesAndScales(configuration.startRotation,
- configuration.endRotation, bugId = 140855415)
- statusBarLayerRotatesScales(configuration.startRotation,
- configuration.endRotation, bugId = 140855415)
+ @Presubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ testSpec.config.endRotation, allStates = false)
- start("appLayerRotates_StartingBounds", bugId = 140855415) {
- hasVisibleRegion(fixedApp.defaultWindowName, startingBounds)
- coversAtMostRegion(startingBounds, pipApp.defaultWindowName)
- }
- end("appLayerRotates_EndingBounds", bugId = 140855415) {
- hasVisibleRegion(fixedApp.defaultWindowName, endingBounds)
- coversAtMostRegion(endingBounds, pipApp.defaultWindowName)
- }
- }
- }
- }
- }
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
- return FlickerTestRunnerFactory.getInstance().buildRotationTest(instrumentation,
- testSpec, supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90),
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun navBarLayerRotatesAndScales() =
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
+ testSpec.config.endRotation)
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun statusBarLayerRotatesScales() =
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
+ testSpec.config.endRotation)
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun appLayerRotates_StartingBounds() {
+ testSpec.assertLayersStart {
+ hasVisibleRegion(fixedApp.defaultWindowName, startingBounds)
+ coversAtMostRegion(startingBounds, pipApp.defaultWindowName)
+ }
+ }
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun appLayerRotates_EndingBounds() {
+ testSpec.assertLayersEnd {
+ hasVisibleRegion(fixedApp.defaultWindowName, endingBounds)
+ coversAtMostRegion(endingBounds, pipApp.defaultWindowName)
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigRotationTests(
+ supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90),
repetitions = 5)
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
index 96b6c912d152..7ba085d3cf1a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
@@ -16,13 +16,14 @@
package com.android.wm.shell.flicker.pip
+import com.android.wm.shell.flicker.FlickerTestBase
import com.android.wm.shell.flicker.helpers.PipAppHelper
import org.junit.Before
abstract class PipTestBase(
rotationName: String,
rotation: Int
-) : AppTestBase(rotationName, rotation) {
+) : FlickerTestBase(rotationName, rotation) {
protected val testApp = PipAppHelper(instrumentation)
@Before
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
index f2d58997d1f2..02389a9ccf87 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
@@ -16,11 +16,15 @@
package com.android.wm.shell.flicker.pip
+import android.os.Bundle
+import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -32,6 +36,7 @@ import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -42,73 +47,89 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class PipToAppTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<Array<Any>> {
- val testSpec = getTransition(eachRun = true) { configuration ->
- setup {
- eachRun {
- this.setRotation(configuration.startRotation)
- }
- }
- teardown {
- eachRun {
- this.setRotation(Surface.ROTATION_0)
- }
+class PipToAppTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = buildTransition(eachRun = true) { configuration ->
+ setup {
+ eachRun {
+ this.setRotation(configuration.startRotation)
}
- transitions {
- pipApp.expandPipWindowToApp(wmHelper)
+ }
+ teardown {
+ eachRun {
+ this.setRotation(Surface.ROTATION_0)
}
- assertions {
- presubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
+ }
+ transitions {
+ pipApp.expandPipWindowToApp(wmHelper)
+ }
+ }
- all("appReplacesPipWindow") {
- this.showsAppWindow(PIP_WINDOW_TITLE)
- .then()
- .showsAppWindowOnTop(pipApp.launcherName)
- }
- }
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- layersTrace {
- statusBarLayerIsAlwaysVisible()
- statusBarLayerRotatesScales(configuration.startRotation,
- Surface.ROTATION_0)
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
- all("appReplacesPipLayer") {
- this.showsLayer(PIP_WINDOW_TITLE)
- .then()
- .showsLayer(pipApp.launcherName)
- }
- }
- }
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
- flaky {
- layersTrace {
- navBarLayerIsAlwaysVisible(bugId = 140855415)
- noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0)
- navBarLayerRotatesAndScales(configuration.startRotation,
- Surface.ROTATION_0, bugId = 140855415)
- }
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- eventLog {
- focusChanges(
- "NexusLauncherActivity", pipApp.launcherName,
- "NexusLauncherActivity", bugId = 151179149)
- }
- }
- }
- }
+ @Presubmit
+ @Test
+ fun appReplacesPipWindow() {
+ testSpec.assertWm {
+ this.showsAppWindow(PIP_WINDOW_TITLE)
+ .then()
+ .showsAppWindowOnTop(pipApp.launcherName)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() =
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+
+ @Presubmit
+ @Test
+ fun appReplacesPipLayer() {
+ testSpec.assertLayers {
+ this.showsLayer(PIP_WINDOW_TITLE)
+ .then()
+ .showsLayer(pipApp.launcherName)
+ }
+ }
- return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation,
- testSpec, supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+ @FlakyTest
+ @Test
+ fun noUncoveredRegions() =
+ testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun navBarLayerRotatesAndScales() =
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+
+ @FlakyTest(bugId = 151179149)
+ @Test
+ fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity",
+ pipApp.launcherName, "NexusLauncherActivity")
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
+ repetitions = 5)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt
index 1b44377425db..968a11de2511 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt
@@ -16,15 +16,19 @@
package com.android.wm.shell.flicker.pip
+import android.os.Bundle
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.startRotation
@@ -32,6 +36,7 @@ import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -42,74 +47,88 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class PipToHomeTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<Array<Any>> {
- val testSpec = getTransition(eachRun = true) { configuration ->
- setup {
- eachRun {
- this.setRotation(configuration.startRotation)
- }
- }
- teardown {
- eachRun {
- this.setRotation(Surface.ROTATION_0)
- }
+class PipToHomeTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = buildTransition(eachRun = true) { configuration ->
+ setup {
+ eachRun {
+ this.setRotation(configuration.startRotation)
}
- transitions {
- pipApp.closePipWindow(wmHelper)
+ }
+ teardown {
+ eachRun {
+ this.setRotation(Surface.ROTATION_0)
}
- assertions {
- presubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
+ }
+ transitions {
+ pipApp.closePipWindow(wmHelper)
+ }
+ }
- all("pipWindowBecomesInvisible") {
- this.showsAppWindow(PIP_WINDOW_TITLE)
- .then()
- .hidesAppWindow(PIP_WINDOW_TITLE)
- }
- }
+ @Postsubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- layersTrace {
- statusBarLayerIsAlwaysVisible()
- statusBarLayerRotatesScales(configuration.startRotation,
- Surface.ROTATION_0)
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
- all("pipLayerBecomesInvisible") {
- this.showsLayer(PIP_WINDOW_TITLE)
- .then()
- .hidesLayer(PIP_WINDOW_TITLE)
- }
- }
- }
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
- postsubmit {
- layersTrace {
- navBarLayerIsAlwaysVisible()
- noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0)
- navBarLayerRotatesAndScales(configuration.startRotation,
- Surface.ROTATION_0)
- }
- }
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- flaky {
- eventLog {
- focusChanges(pipApp.launcherName, "NexusLauncherActivity",
- bugId = 151179149)
- }
- }
- }
- }
+ @Presubmit
+ @Test
+ fun pipWindowBecomesInvisible() {
+ testSpec.assertWm {
+ this.showsAppWindow(PIP_WINDOW_TITLE)
+ .then()
+ .hidesAppWindow(PIP_WINDOW_TITLE)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun pipLayerBecomesInvisible() {
+ testSpec.assertLayers {
+ this.showsLayer(PIP_WINDOW_TITLE)
+ .then()
+ .hidesLayer(PIP_WINDOW_TITLE)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() =
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
- return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation,
- testSpec, supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+ @Postsubmit
+ @Test
+ fun noUncoveredRegions() =
+ testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
+
+ @Postsubmit
+ @Test
+ fun navBarLayerRotatesAndScales() =
+ testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
+
+ @FlakyTest(bugId = 151179149)
+ @Test
+ fun focusChanges() = testSpec.focusChanges(pipApp.launcherName, "NexusLauncherActivity")
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
+ repetitions = 5)
}
}
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransitionBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index b1e404e4c8e6..a94483ec00a0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransitionBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -20,16 +20,26 @@ import android.app.Instrumentation
import android.content.Intent
import android.os.Bundle
import android.view.Surface
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
import com.android.wm.shell.flicker.helpers.PipAppHelper
import com.android.wm.shell.flicker.removeAllTasksButHome
import com.android.wm.shell.flicker.testapp.Components
-abstract class PipTransitionBase(protected val instrumentation: Instrumentation) {
+abstract class PipTransition(protected val testSpec: FlickerTestParameter) {
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ protected val isRotated = testSpec.config.startRotation.isRotated()
+ protected val pipApp = PipAppHelper(instrumentation)
+ protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation)
+ protected abstract val transition: FlickerBuilder.(Bundle) -> Unit
+
// Helper class to process test actions by broadcast.
protected class BroadcastActionTrigger(private val instrumentation: Instrumentation) {
private fun createIntentWithAction(broadcastAction: String): Intent {
@@ -59,16 +69,20 @@ abstract class PipTransitionBase(protected val instrumentation: Instrumentation)
}
}
- protected val pipApp = PipAppHelper(instrumentation)
- protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation)
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ transition(this, testSpec.config)
+ }
+ }
/**
* Gets a configuration that handles basic setup and teardown of pip tests
*/
protected val setupAndTeardown: FlickerBuilder.(Bundle) -> Unit
- get() = { configuration ->
- withTestName { buildTestTag(configuration) }
- repeat { configuration.repetitions }
+ get() = {
setup {
test {
removeAllTasksButHome()
@@ -81,7 +95,7 @@ abstract class PipTransitionBase(protected val instrumentation: Instrumentation)
}
test {
removeAllTasksButHome()
- pipApp.exit()
+ pipApp.exit(wmHelper)
}
}
}
@@ -95,7 +109,7 @@ abstract class PipTransitionBase(protected val instrumentation: Instrumentation)
* @param extraSpec Addicional segment of flicker specification
*/
@JvmOverloads
- open fun getTransition(
+ protected open fun buildTransition(
eachRun: Boolean,
stringExtras: Map<String, String> = mapOf(Components.PipActivity.EXTRA_ENTER_PIP to "true"),
extraSpec: FlickerBuilder.(Bundle) -> Unit = {}
@@ -121,12 +135,12 @@ abstract class PipTransitionBase(protected val instrumentation: Instrumentation)
teardown {
eachRun {
if (eachRun) {
- pipApp.exit()
+ pipApp.exit(wmHelper)
}
}
test {
if (!eachRun) {
- pipApp.exit()
+ pipApp.exit(wmHelper)
}
removeAllTasksButHome()
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index c01bc94151e9..1f0370dc0505 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -16,21 +16,26 @@
package com.android.wm.shell.flicker.pip
+import android.os.Bundle
+import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.pip.PipTransitionBase.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
+import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION
import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
import org.junit.Assert.assertEquals
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -41,75 +46,99 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class SetRequestedOrientationWhilePinnedTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<Array<Any>> {
- return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation,
- supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 1) { configuration ->
- setupAndTeardown(this, configuration)
+ testSpec: FlickerTestParameter
+) : PipTransition(testSpec) {
+ private val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0)
+ private val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90)
- setup {
- eachRun {
- // Launch the PiP activity fixed as landscape
- pipApp.launchViaIntent(wmHelper, stringExtras = mapOf(
- EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString(),
- EXTRA_ENTER_PIP to "true"))
- }
- }
- teardown {
- eachRun {
- pipApp.exit()
- }
- }
- transitions {
- // Request that the orientation is set to landscape
- broadcastActionTrigger.requestOrientationForPip(ORIENTATION_LANDSCAPE)
+ override val transition: FlickerBuilder.(Bundle) -> Unit
+ get() = { configuration ->
+ setupAndTeardown(this, configuration)
- // Launch the activity back into fullscreen and
- // ensure that it is now in landscape
- pipApp.launchViaIntent(wmHelper)
- wmHelper.waitForFullScreenApp(pipApp.component)
- wmHelper.waitForRotation(Surface.ROTATION_90)
- assertEquals(Surface.ROTATION_90, device.displayRotation)
+ setup {
+ eachRun {
+ // Launch the PiP activity fixed as landscape
+ pipApp.launchViaIntent(wmHelper, stringExtras = mapOf(
+ EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString(),
+ EXTRA_ENTER_PIP to "true"))
}
- assertions {
- val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0)
- val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90)
- presubmit {
- windowManagerTrace {
- start("PIP window must remain inside display") {
- coversAtMostRegion(pipApp.defaultWindowName, startingBounds)
- }
- end("pipApp shows on top") {
- showsAppWindowOnTop(pipApp.defaultWindowName)
- }
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- }
- layersTrace {
- start("PIP layer must remain inside display") {
- coversAtMostRegion(startingBounds, pipApp.defaultWindowName)
- }
- end("pipApp layer covers fullscreen") {
- hasVisibleRegion(pipApp.defaultWindowName, endingBounds)
- }
- }
- }
-
- flaky {
- layersTrace {
- navBarLayerIsAlwaysVisible(bugId = 140855415)
- statusBarLayerIsAlwaysVisible(bugId = 140855415)
- }
- }
+ }
+ teardown {
+ eachRun {
+ pipApp.exit(wmHelper)
}
}
+ transitions {
+ // Request that the orientation is set to landscape
+ broadcastActionTrigger.requestOrientationForPip(ORIENTATION_LANDSCAPE)
+
+ // Launch the activity back into fullscreen and
+ // ensure that it is now in landscape
+ pipApp.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(pipApp.component)
+ wmHelper.waitForRotation(Surface.ROTATION_90)
+ assertEquals(Surface.ROTATION_90, device.displayRotation)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun pipWindowInsideDisplay() {
+ testSpec.assertWmStart {
+ coversAtMostRegion(pipApp.defaultWindowName, startingBounds)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun pipAppShowsOnTop() {
+ testSpec.assertWmEnd {
+ showsAppWindowOnTop(pipApp.defaultWindowName)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun pipLayerInsideDisplay() {
+ testSpec.assertLayersStart {
+ coversAtMostRegion(startingBounds, pipApp.defaultWindowName)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun pipAppLayerCoversFullScreen() {
+ testSpec.assertLayersEnd {
+ hasVisibleRegion(pipApp.defaultWindowName, endingBounds)
+ }
+ }
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
+ repetitions = 1)
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp
index 26627a47ee62..ea606df1536d 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test {
name: "WMShellFlickerTestApp",
srcs: ["**/*.java"],
@@ -23,4 +32,4 @@ java_library {
name: "wmshell-flicker-test-components",
srcs: ["src/**/Components.java"],
sdk_version: "test_current",
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
index e094158e1144..27c626170a4b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
@@ -20,17 +20,17 @@ import static org.mockito.Mockito.mock;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
-import org.mockito.Mock;
-
public class TestAppPairsController extends AppPairsController {
private TestAppPairsPool mPool;
public TestAppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue,
DisplayController displayController) {
- super(organizer, syncQueue, displayController, mock(ShellExecutor.class));
+ super(organizer, syncQueue, displayController, mock(ShellExecutor.class),
+ mock(DisplayImeController.class));
mPool = new TestAppPairsPool(this);
setPairsPool(mPool);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
index 416028088294..bdf75fcd8816 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.bubbles.storage
+import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.wm.shell.ShellTestCase
@@ -31,9 +32,10 @@ import org.junit.runner.RunWith
class BubblePersistentRepositoryTest : ShellTestCase() {
private val bubbles = listOf(
- BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0),
- BubbleEntity(10, "com.example.chat", "alice and bob", "key-2", 0, 16537428, "title"),
- BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0)
+ BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0, null, 1),
+ BubbleEntity(10, "com.example.chat", "alice and bob", "key-2", 0, 16537428, "title", 2),
+ BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0, null,
+ INVALID_TASK_ID)
)
private lateinit var repository: BubblePersistentRepository
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
index dd1a6a5a281e..05795fde7d6c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.bubbles.storage
+import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.content.pm.LauncherApps
import android.os.UserHandle
import android.testing.AndroidTestingRunner
@@ -37,10 +38,12 @@ class BubbleVolatileRepositoryTest : ShellTestCase() {
private val user0 = UserHandle.of(0)
private val user10 = UserHandle.of(10)
- private val bubble1 = BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0)
+ private val bubble1 = BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0,
+ null, 1)
private val bubble2 = BubbleEntity(10, "com.example.chat", "alice and bob",
- "key-2", 0, 16537428, "title")
- private val bubble3 = BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0)
+ "key-2", 0, 16537428, "title", 2)
+ private val bubble3 = BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0,
+ null, INVALID_TASK_ID)
private val bubbles = listOf(bubble1, bubble2, bubble3)
@@ -105,13 +108,13 @@ class BubbleVolatileRepositoryTest : ShellTestCase() {
@Test
fun testAddBubbleMatchesByKey() {
- val bubble = BubbleEntity(0, "com.example.pkg", "shortcut-id", "key", 120, 0, "title")
+ val bubble = BubbleEntity(0, "com.example.pkg", "shortcut-id", "key", 120, 0, "title", 1)
repository.addBubbles(listOf(bubble))
assertEquals(bubble, repository.bubbles.get(0))
// Same key as first bubble but different entry
val bubbleModified = BubbleEntity(0, "com.example.pkg", "shortcut-id", "key", 120, 0,
- "different title")
+ "different title", 2)
repository.addBubbles(listOf(bubbleModified))
assertEquals(bubbleModified, repository.bubbles.get(0))
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
index e0891a95c6a6..839b873d0c23 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.bubbles.storage
+import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.wm.shell.ShellTestCase
@@ -31,17 +32,18 @@ import java.io.ByteArrayOutputStream
class BubbleXmlHelperTest : ShellTestCase() {
private val bubbles = listOf(
- BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0),
- BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428, "title"),
- BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0)
+ BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0, null, 1),
+ BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428, "title", 2),
+ BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0, null,
+ INVALID_TASK_ID)
)
@Test
fun testWriteXml() {
val expectedEntries = """
-<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
-<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" />
-<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" tid="1" />
+<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" tid="2" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" tid="-1" />
""".trimIndent()
ByteArrayOutputStream().use {
writeXml(it, bubbles)
@@ -56,9 +58,9 @@ class BubbleXmlHelperTest : ShellTestCase() {
val src = """
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<bs v="1">
-<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
-<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" />
-<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" tid="1" />
+<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" tid="2" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" tid="-1" />
</bs>
""".trimIndent()
val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
@@ -79,4 +81,32 @@ class BubbleXmlHelperTest : ShellTestCase() {
val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
assertEquals("failed parsing bubbles from xml\n$src", emptyList<BubbleEntity>(), actual)
}
+
+ /**
+ * In S we changed the XML to include a taskId, version didn't increase because we can set a
+ * reasonable default for taskId (INVALID_TASK_ID) if it wasn't in the XML previously, this
+ * tests that that works.
+ */
+ @Test
+ fun testReadXMLWithoutTaskId() {
+ val expectedBubbles = listOf(
+ BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0, null,
+ INVALID_TASK_ID),
+ BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428, "title",
+ INVALID_TASK_ID),
+ BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0, null,
+ INVALID_TASK_ID)
+ )
+
+ val src = """
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<bs v="1">
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
+<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
+</bs>
+ """.trimIndent()
+ val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
+ assertEquals("failed parsing bubbles from xml\n$src", expectedBubbles, actual)
+ }
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java
index 2b5b77e49e3a..88e754c58792 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java
@@ -38,6 +38,12 @@ import com.android.internal.R;
import org.junit.Test;
+/**
+ * Tests for {@link DisplayLayout}.
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:DisplayLayoutTest
+ */
@SmallTest
public class DisplayLayoutTest {
@@ -70,18 +76,6 @@ public class DisplayLayoutTest {
@Test
public void testRotate() {
// Basic rotate utility
- Rect testParent = new Rect(0, 0, 1000, 600);
- Rect testInner = new Rect(40, 20, 120, 80);
- Rect testResult = new Rect(testInner);
- DisplayLayout.rotateBounds(testResult, testParent, 1);
- assertEquals(new Rect(20, 880, 80, 960), testResult);
- testResult.set(testInner);
- DisplayLayout.rotateBounds(testResult, testParent, 2);
- assertEquals(new Rect(880, 20, 960, 80), testResult);
- testResult.set(testInner);
- DisplayLayout.rotateBounds(testResult, testParent, 3);
- assertEquals(new Rect(520, 40, 580, 120), testResult);
-
Resources res = createResources(40, 50, false, 30, 40);
DisplayInfo info = createDisplayInfo(1000, 1500, 60, ROTATION_0);
DisplayLayout dl = new DisplayLayout(info, res, true, true);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
index 21bc32c6563c..d8aebc284bf1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
@@ -198,7 +198,7 @@ public class TaskStackListenerImplTest {
@Test
public void testOnActivityDismissingDockedStack() {
- mImpl.onActivityDismissingDockedStack();
+ mImpl.onActivityDismissingDockedTask();
verify(mCallback).onActivityDismissingDockedStack();
verify(mOtherCallback).onActivityDismissingDockedStack();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index 5821eed6f611..7b0e6b9a5ed7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -36,6 +36,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.DisplayImeController;
import org.junit.Before;
import org.junit.Test;
@@ -49,6 +50,7 @@ import org.mockito.MockitoAnnotations;
public class SplitLayoutTests extends ShellTestCase {
@Mock SplitLayout.LayoutChangeListener mLayoutChangeListener;
@Mock SurfaceControl mRootLeash;
+ @Mock DisplayImeController mDisplayImeController;
private SplitLayout mSplitLayout;
@Before
@@ -59,7 +61,8 @@ public class SplitLayoutTests extends ShellTestCase {
mContext,
getConfiguration(false),
mLayoutChangeListener,
- b -> b.setParent(mRootLeash));
+ b -> b.setParent(mRootLeash),
+ mDisplayImeController);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
index 698315a77d8e..86d0d82222e4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
@@ -29,6 +29,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.DisplayImeController;
import org.junit.Before;
import org.junit.Test;
@@ -42,6 +43,7 @@ import org.mockito.MockitoAnnotations;
public class SplitWindowManagerTests extends ShellTestCase {
@Mock SurfaceControl mSurfaceControl;
@Mock SplitLayout mSplitLayout;
+ @Mock DisplayImeController mDisplayImeController;
private SplitWindowManager mSplitWindowManager;
@Before
@@ -50,7 +52,7 @@ public class SplitWindowManagerTests extends ShellTestCase {
final Configuration configuration = new Configuration();
configuration.setToDefaults();
mSplitWindowManager = new SplitWindowManager("TestSplitDivider", mContext, configuration,
- b -> b.setParent(mSurfaceControl));
+ b -> b.setParent(mSurfaceControl), mDisplayImeController);
when(mSplitLayout.getDividerBounds()).thenReturn(
new Rect(0, 0, configuration.windowConfiguration.getBounds().width(),
configuration.windowConfiguration.getBounds().height()));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
index 3147dab1a0f8..63b94139dd9c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.pip;
+import static android.util.RotationUtils.rotateBounds;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_90;
@@ -37,7 +38,6 @@ import android.view.SurfaceControl;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.DisplayLayout;
import org.junit.Before;
import org.junit.Test;
@@ -141,7 +141,7 @@ public class PipAnimationControllerTest extends ShellTestCase {
// Apply fraction 1 to compute the end value.
animator.applySurfaceControlTransaction(mLeash, new DummySurfaceControlTx(), 1);
final Rect rotatedEndBounds = new Rect(endBounds);
- DisplayLayout.rotateBounds(rotatedEndBounds, endBounds, ROTATION_90);
+ rotateBounds(rotatedEndBounds, endBounds, ROTATION_90);
assertEquals("Expect 90 degree rotated bounds", rotatedEndBounds, animator.mCurrentValue);
}
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 cfe84639d24e..f2b4e9761226 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
@@ -124,7 +124,7 @@ public class PipControllerTest extends ShellTestCase {
final ComponentName component1 = new ComponentName(mContext, "component1");
when(mMockPipBoundsState.getLastPipComponentName()).thenReturn(component1);
- mPipController.mPinnedStackListener.onActivityHidden(component1);
+ mPipController.mPinnedTaskListener.onActivityHidden(component1);
verify(mMockPipBoundsState).setLastPipComponentName(null);
}
@@ -135,7 +135,7 @@ public class PipControllerTest extends ShellTestCase {
final ComponentName component2 = new ComponentName(mContext, "component2");
when(mMockPipBoundsState.getLastPipComponentName()).thenReturn(component1);
- mPipController.mPinnedStackListener.onActivityHidden(component2);
+ mPipController.mPinnedTaskListener.onActivityHidden(component2);
verify(mMockPipBoundsState, never()).setLastPipComponentName(null);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index d2d18129d071..74753aac4a24 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -41,6 +41,7 @@ import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
+import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.SyncTransactionQueue;
import org.junit.Before;
@@ -58,13 +59,14 @@ public class StageCoordinatorTests extends ShellTestCase {
@Mock private RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
@Mock private MainStage mMainStage;
@Mock private SideStage mSideStage;
+ @Mock private DisplayImeController mDisplayImeController;
private StageCoordinator mStageCoordinator;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mStageCoordinator = new TestStageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
- mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage);
+ mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage, mDisplayImeController);
}
@Test
@@ -94,9 +96,9 @@ public class StageCoordinatorTests extends ShellTestCase {
TestStageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
- MainStage mainStage, SideStage sideStage) {
+ MainStage mainStage, SideStage sideStage, DisplayImeController imeController) {
super(context, displayId, syncQueue, rootTDAOrganizer, taskOrganizer, mainStage,
- sideStage);
+ sideStage, imeController);
// Prepare default TaskDisplayArea for testing.
mDisplayAreaInfo = new DisplayAreaInfo(
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 5eca3e75a7b8..926108c41e5e 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
@@ -41,6 +41,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -58,6 +59,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.ShellExecutor;
@@ -78,6 +80,8 @@ public class ShellTransitionTests {
private final WindowOrganizer mOrganizer = mock(WindowOrganizer.class);
private final TransactionPool mTransactionPool = mock(TransactionPool.class);
+ private final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
private final TestShellExecutor mMainExecutor = new TestShellExecutor();
private final ShellExecutor mAnimExecutor = new TestShellExecutor();
private final TestTransitionHandler mDefaultHandler = new TestTransitionHandler();
@@ -90,8 +94,8 @@ public class ShellTransitionTests {
@Test
public void testBasicTransitionFlow() {
- Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mMainExecutor,
- mAnimExecutor);
+ Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
+ mMainExecutor, mAnimExecutor);
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
IBinder transitToken = new Binder();
@@ -109,8 +113,8 @@ public class ShellTransitionTests {
@Test
public void testNonDefaultHandler() {
- Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mMainExecutor,
- mAnimExecutor);
+ Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
+ mMainExecutor, mAnimExecutor);
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
@@ -188,8 +192,8 @@ public class ShellTransitionTests {
@Test
public void testRequestRemoteTransition() {
- Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mMainExecutor,
- mAnimExecutor);
+ Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
+ mMainExecutor, mAnimExecutor);
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
final boolean[] remoteCalled = new boolean[]{false};
@@ -255,8 +259,8 @@ public class ShellTransitionTests {
@Test
public void testRegisteredRemoteTransition() {
- Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mMainExecutor,
- mAnimExecutor);
+ Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
+ mMainExecutor, mAnimExecutor);
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
final boolean[] remoteCalled = new boolean[]{false};
diff --git a/libs/androidfw/TEST_MAPPING b/libs/androidfw/TEST_MAPPING
index 777aa0b429e5..766714cd7694 100644
--- a/libs/androidfw/TEST_MAPPING
+++ b/libs/androidfw/TEST_MAPPING
@@ -1,10 +1,6 @@
{
"presubmit": [
{
- "name": "libandroidfw_tests",
- "host": true
- },
- {
"name": "CtsResourcesLoaderTests"
}
]
diff --git a/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp b/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp
index b36ff0968ba3..3035a79f668d 100644
--- a/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp
+++ b/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp
@@ -1,3 +1,12 @@
+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_libs_androidfw_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_libs_androidfw_license"],
+}
+
cc_fuzz {
name: "cursorwindow_fuzzer",
srcs: [
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
index 5d3f6f2f28c9..2448cc904104 100644
--- a/libs/hwui/FrameInfo.cpp
+++ b/libs/hwui/FrameInfo.cpp
@@ -20,13 +20,12 @@
namespace android {
namespace uirenderer {
-const std::array<std::string, static_cast<int>(FrameInfoIndex::NumIndexes)> FrameInfoNames = {
+const std::array FrameInfoNames{
"Flags",
"FrameTimelineVsyncId",
"IntendedVsync",
"Vsync",
- "OldestInputEvent",
- "NewestInputEvent",
+ "InputEventId",
"HandleInputStart",
"AnimationStart",
"PerformTraversalsStart",
@@ -40,7 +39,8 @@ const std::array<std::string, static_cast<int>(FrameInfoIndex::NumIndexes)> Fram
"DequeueBufferDuration",
"QueueBufferDuration",
"GpuCompleted",
- "SwapBuffersCompleted"
+ "SwapBuffersCompleted",
+ "DisplayPresentTime",
};
static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 20,
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index 45a367f525da..912d04c5d87d 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -28,15 +28,14 @@
namespace android {
namespace uirenderer {
-#define UI_THREAD_FRAME_INFO_SIZE 11
+static constexpr size_t UI_THREAD_FRAME_INFO_SIZE = 10;
enum class FrameInfoIndex {
Flags = 0,
FrameTimelineVsyncId,
IntendedVsync,
Vsync,
- OldestInputEvent,
- NewestInputEvent,
+ InputEventId,
HandleInputStart,
AnimationStart,
PerformTraversalsStart,
@@ -56,13 +55,14 @@ enum class FrameInfoIndex {
GpuCompleted,
SwapBuffersCompleted,
+ DisplayPresentTime,
// Must be the last value!
// Also must be kept in sync with FrameMetrics.java#FRAME_STATS_COUNT
NumIndexes
};
-extern const std::array<std::string, static_cast<int>(FrameInfoIndex::NumIndexes)> FrameInfoNames;
+extern const std::array<const char*, static_cast<int>(FrameInfoIndex::NumIndexes)> FrameInfoNames;
namespace FrameInfoFlags {
enum {
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 2cd9b7b39174..4eefe921fbe9 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -112,7 +112,7 @@ void JankTracker::finishFrame(const FrameInfo& frame) {
std::lock_guard lock(mDataMutex);
// Fast-path for jank-free frames
- int64_t totalDuration = frame.duration(sFrameStart, FrameInfoIndex::FrameCompleted);
+ int64_t totalDuration = frame.duration(sFrameStart, FrameInfoIndex::SwapBuffersCompleted);
if (mDequeueTimeForgiveness && frame[FrameInfoIndex::DequeueBufferDuration] > 500_us) {
nsecs_t expectedDequeueDuration = mDequeueTimeForgiveness + frame[FrameInfoIndex::Vsync] -
frame[FrameInfoIndex::IssueDrawCommandsStart];
@@ -219,7 +219,7 @@ void JankTracker::dumpData(int fd, const ProfileDataDescription* description,
void JankTracker::dumpFrames(int fd) {
dprintf(fd, "\n\n---PROFILEDATA---\n");
for (size_t i = 0; i < static_cast<size_t>(FrameInfoIndex::NumIndexes); i++) {
- dprintf(fd, "%s", FrameInfoNames[i].c_str());
+ dprintf(fd, "%s", FrameInfoNames[i]);
dprintf(fd, ",");
}
for (size_t i = 0; i < mFrames.size(); i++) {
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 1fddac4cd05d..28d2b4cec0e1 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -188,7 +188,7 @@ void SkiaCanvas::restoreUnclippedLayer(int restoreCount, const SkPaint& paint) {
}
if (mCanvas->getSaveCount() == restoreCount + 1) {
- SkCanvasPriv::DrawBehind(mCanvas, *filterPaint(paint));
+ SkCanvasPriv::DrawBehind(mCanvas, filterPaint(paint));
this->restore();
}
}
@@ -431,15 +431,14 @@ void SkiaCanvas::drawColor(int color, SkBlendMode mode) {
mCanvas->drawColor(color, mode);
}
-SkiaCanvas::PaintCoW&& SkiaCanvas::filterPaint(PaintCoW&& paint) const {
+void SkiaCanvas::onFilterPaint(SkPaint& paint) {
if (mPaintFilter) {
- mPaintFilter->filter(&paint.writeable());
+ mPaintFilter->filter(&paint);
}
- return std::move(paint);
}
void SkiaCanvas::drawPaint(const SkPaint& paint) {
- mCanvas->drawPaint(*filterPaint(paint));
+ mCanvas->drawPaint(filterPaint(paint));
}
// ----------------------------------------------------------------------------
@@ -457,13 +456,11 @@ void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint,
points += 2;
}
- apply_looper(&paint, [&](const SkPaint& p) {
- mCanvas->drawPoints(mode, count, pts.get(), p);
- });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawPoints(mode, count, pts.get(), p); });
}
void SkiaCanvas::drawPoint(float x, float y, const Paint& paint) {
- apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawPoint(x, y, p); });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawPoint(x, y, p); });
}
void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint) {
@@ -472,9 +469,8 @@ void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint)
void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
const Paint& paint) {
- apply_looper(&paint, [&](const SkPaint& p) {
- mCanvas->drawLine(startX, startY, stopX, stopY, p);
- });
+ applyLooper(&paint,
+ [&](const SkPaint& p) { mCanvas->drawLine(startX, startY, stopX, stopY, p); });
}
void SkiaCanvas::drawLines(const float* points, int count, const Paint& paint) {
@@ -484,46 +480,44 @@ void SkiaCanvas::drawLines(const float* points, int count, const Paint& paint) {
void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
- apply_looper(&paint, [&](const SkPaint& p) {
+ applyLooper(&paint, [&](const SkPaint& p) {
mCanvas->drawRect({left, top, right, bottom}, p);
});
}
void SkiaCanvas::drawRegion(const SkRegion& region, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
- apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawRegion(region, p); });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawRegion(region, p); });
}
void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
- apply_looper(&paint, [&](const SkPaint& p) {
- mCanvas->drawRoundRect(rect, rx, ry, p);
- });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawRoundRect(rect, rx, ry, p); });
}
void SkiaCanvas::drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
const Paint& paint) {
- apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawDRRect(outer, inner, p); });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawDRRect(outer, inner, p); });
}
void SkiaCanvas::drawCircle(float x, float y, float radius, const Paint& paint) {
if (CC_UNLIKELY(radius <= 0 || paint.nothingToDraw())) return;
- apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawCircle(x, y, radius, p); });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawCircle(x, y, radius, p); });
}
void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
- apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawOval(oval, p); });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawOval(oval, p); });
}
void SkiaCanvas::drawArc(float left, float top, float right, float bottom, float startAngle,
float sweepAngle, bool useCenter, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
- apply_looper(&paint, [&](const SkPaint& p) {
+ applyLooper(&paint, [&](const SkPaint& p) {
if (fabs(sweepAngle) >= 360.0f) {
mCanvas->drawOval(arc, p);
} else {
@@ -537,13 +531,11 @@ void SkiaCanvas::drawPath(const SkPath& path, const Paint& paint) {
if (CC_UNLIKELY(path.isEmpty() && (!path.isInverseFillType()))) {
return;
}
- apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawPath(path, p); });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawPath(path, p); });
}
void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const Paint& paint) {
- apply_looper(&paint, [&](const SkPaint& p) {
- mCanvas->drawVertices(vertices, mode, p);
- });
+ applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawVertices(vertices, mode, p); });
}
// ----------------------------------------------------------------------------
@@ -552,7 +544,7 @@ void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, cons
void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
auto image = bitmap.makeImage();
- apply_looper(paint, [&](const SkPaint& p) {
+ applyLooper(paint, [&](const SkPaint& p) {
auto sampling = SkSamplingOptions(p.getFilterQuality());
mCanvas->drawImage(image, left, top, sampling, &p);
});
@@ -562,7 +554,7 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint*
auto image = bitmap.makeImage();
SkAutoCanvasRestore acr(mCanvas, true);
mCanvas->concat(matrix);
- apply_looper(paint, [&](const SkPaint& p) {
+ applyLooper(paint, [&](const SkPaint& p) {
auto sampling = SkSamplingOptions(p.getFilterQuality());
mCanvas->drawImage(image, 0, 0, sampling, &p);
});
@@ -575,7 +567,7 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float s
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- apply_looper(paint, [&](const SkPaint& p) {
+ applyLooper(paint, [&](const SkPaint& p) {
auto sampling = SkSamplingOptions(p.getFilterQuality());
mCanvas->drawImageRect(image, srcRect, dstRect, sampling, &p,
SkCanvas::kFast_SrcRectConstraint);
@@ -672,11 +664,11 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
pnt.setShader(image->makeShader(sampling));
auto v = builder.detach();
- apply_looper(&pnt, [&](const SkPaint& p) {
+ applyLooper(&pnt, [&](const SkPaint& p) {
SkPaint copy(p);
auto s = SkSamplingOptions(p.getFilterQuality());
if (s != sampling) {
- // apply_looper changed the quality?
+ // applyLooper changed the quality?
copy.setShader(image->makeShader(s));
}
mCanvas->drawVertices(v, SkBlendMode::kModulate, copy);
@@ -707,7 +699,7 @@ void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, floa
lattice.fBounds = nullptr;
SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
auto image = bitmap.makeImage();
- apply_looper(paint, [&](const SkPaint& p) {
+ applyLooper(paint, [&](const SkPaint& p) {
auto filter = SkSamplingOptions(p.getFilterQuality()).filter;
mCanvas->drawImageLattice(image.get(), lattice, dst, filter, &p);
});
@@ -746,9 +738,7 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& pai
sk_sp<SkTextBlob> textBlob(builder.make());
- apply_looper(&paintCopy, [&](const SkPaint& p) {
- mCanvas->drawTextBlob(textBlob, 0, 0, p);
- });
+ applyLooper(&paintCopy, [&](const SkPaint& p) { mCanvas->drawTextBlob(textBlob, 0, 0, p); });
drawTextDecorations(x, y, totalAdvance, paintCopy);
}
@@ -788,9 +778,7 @@ void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset,
sk_sp<SkTextBlob> textBlob(builder.make());
- apply_looper(&paintCopy, [&](const SkPaint& p) {
- mCanvas->drawTextBlob(textBlob, 0, 0, p);
- });
+ applyLooper(&paintCopy, [&](const SkPaint& p) { mCanvas->drawTextBlob(textBlob, 0, 0, p); });
}
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index eac3f2217bd8..9ab2b106dbfa 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -169,53 +169,24 @@ protected:
const Paint& paint, const SkPath& path, size_t start,
size_t end) override;
- /** This class acts as a copy on write SkPaint.
- *
- * Initially this will be the SkPaint passed to the contructor.
- * The first time writable() is called this will become a copy of the
- * initial SkPaint (or a default SkPaint if nullptr).
- */
- struct PaintCoW {
- PaintCoW(const SkPaint& that) : mPtr(&that) {}
- PaintCoW(const SkPaint* ptr) : mPtr(ptr) {}
- PaintCoW(const PaintCoW&) = delete;
- PaintCoW(PaintCoW&&) = delete;
- PaintCoW& operator=(const PaintCoW&) = delete;
- PaintCoW& operator=(PaintCoW&&) = delete;
- SkPaint& writeable() {
- if (!mStorage) {
- if (!mPtr) {
- mStorage.emplace();
- } else {
- mStorage.emplace(*mPtr);
- }
- mPtr = &*mStorage;
- }
- return *mStorage;
- }
- operator const SkPaint*() const { return mPtr; }
- const SkPaint* operator->() const { assert(mPtr); return mPtr; }
- explicit operator bool() { return mPtr != nullptr; }
- private:
- const SkPaint* mPtr;
- std::optional<SkPaint> mStorage;
- };
+ void onFilterPaint(SkPaint& paint);
- /** Filters the paint using the current paint filter.
- *
- * @param paint the paint to filter. Will be initialized with the default
- * SkPaint before filtering if filtering is required.
- */
- PaintCoW&& filterPaint(PaintCoW&& paint) const;
+ SkPaint filterPaint(const SkPaint& src) {
+ SkPaint dst(src);
+ this->onFilterPaint(dst);
+ return dst;
+ }
// proc(const SkPaint& modifiedPaint)
- template <typename Proc> void apply_looper(const Paint* paint, Proc proc) {
- SkPaint skp;
- BlurDrawLooper* looper = nullptr;
- if (paint) {
- skp = *filterPaint(paint);
- looper = paint->getLooper();
+ template <typename Proc>
+ void applyLooper(const Paint* paint, Proc proc, void (*preFilter)(SkPaint&) = nullptr) {
+ BlurDrawLooper* looper = paint ? paint->getLooper() : nullptr;
+ const SkPaint* skpPtr = paint;
+ SkPaint skp = skpPtr ? *skpPtr : SkPaint();
+ if (preFilter) {
+ preFilter(skp);
}
+ this->onFilterPaint(skp);
if (looper) {
looper->apply(skp, [&](SkPoint offset, const SkPaint& modifiedPaint) {
mCanvas->save();
@@ -228,7 +199,6 @@ protected:
}
}
-
private:
struct SaveRec {
int saveCount;
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index df66981853bb..f24ba5c1c878 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -240,8 +240,8 @@ static void android_view_ThreadedRenderer_setSdrWhitePoint(JNIEnv* env, jobject
static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
- "Mismatched size expectations, given %d expected %d",
- frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
+ "Mismatched size expectations, given %d expected %zu", frameInfoSize,
+ UI_THREAD_FRAME_INFO_SIZE);
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
return proxy->syncAndDrawFrame();
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 04e3a1cb887e..af7271e96cb9 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -170,36 +170,23 @@ void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
// Recording Canvas draw operations: Bitmaps
// ----------------------------------------------------------------------------
-SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint) {
- bool fixBlending = false;
- bool fixAA = false;
- if (paint) {
- // kClear blend mode is drawn as kDstOut on HW for compatibility with Android O and
- // older.
- fixBlending = sApiLevel <= 27 && paint->getBlendMode() == SkBlendMode::kClear;
- fixAA = paint->isAntiAlias();
+void SkiaRecordingCanvas::FilterForImage(SkPaint& paint) {
+ // kClear blend mode is drawn as kDstOut on HW for compatibility with Android O and
+ // older.
+ if (sApiLevel <= 27 && paint.getBlendMode() == SkBlendMode::kClear) {
+ paint.setBlendMode(SkBlendMode::kDstOut);
}
- if (fixBlending || fixAA) {
- SkPaint& tmpPaint = paint.writeable();
-
- if (fixBlending) {
- tmpPaint.setBlendMode(SkBlendMode::kDstOut);
- }
-
- // disabling AA on bitmap draws matches legacy HWUI behavior
- tmpPaint.setAntiAlias(false);
- }
-
- return filterPaint(std::move(paint));
+ // disabling AA on bitmap draws matches legacy HWUI behavior
+ paint.setAntiAlias(false);
}
-static SkFilterMode Paint_to_filter(const SkPaint* paint) {
- return paint && paint->getFilterQuality() != kNone_SkFilterQuality ? SkFilterMode::kLinear
- : SkFilterMode::kNearest;
+static SkFilterMode Paint_to_filter(const SkPaint& paint) {
+ return paint.getFilterQuality() != kNone_SkFilterQuality ? SkFilterMode::kLinear
+ : SkFilterMode::kNearest;
}
-static SkSamplingOptions Paint_to_sampling(const SkPaint* paint) {
+static SkSamplingOptions Paint_to_sampling(const SkPaint& paint) {
// Android only has 1-bit for "filter", so we don't try to cons-up mipmaps or cubics
return SkSamplingOptions(Paint_to_filter(paint), SkMipmapMode::kNone);
}
@@ -207,9 +194,12 @@ static SkSamplingOptions Paint_to_sampling(const SkPaint* paint) {
void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
sk_sp<SkImage> image = bitmap.makeImage();
- applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
- mRecorder.drawImage(image, left + x, top + y, Paint_to_sampling(p), p, bitmap.palette());
- });
+ applyLooper(
+ paint,
+ [&](const SkPaint& p) {
+ mRecorder.drawImage(image, left, top, Paint_to_sampling(p), &p, bitmap.palette());
+ },
+ FilterForImage);
// if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
// it is not safe to store a raw SkImage pointer, because the image object will be destroyed
@@ -225,9 +215,12 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, con
sk_sp<SkImage> image = bitmap.makeImage();
- applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
- mRecorder.drawImage(image, x, y, Paint_to_sampling(p), p, bitmap.palette());
- });
+ applyLooper(
+ paint,
+ [&](const SkPaint& p) {
+ mRecorder.drawImage(image, 0, 0, Paint_to_sampling(p), &p, bitmap.palette());
+ },
+ FilterForImage);
if (!bitmap.isImmutable() && image.get() && !image->unique()) {
mDisplayList->mMutableImages.push_back(image.get());
@@ -242,10 +235,13 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop
sk_sp<SkImage> image = bitmap.makeImage();
- applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
- mRecorder.drawImageRect(image, srcRect, dstRect.makeOffset(x, y), Paint_to_sampling(p),
- p, SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
- });
+ applyLooper(
+ paint,
+ [&](const SkPaint& p) {
+ mRecorder.drawImageRect(image, srcRect, dstRect, Paint_to_sampling(p), &p,
+ SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
+ },
+ FilterForImage);
if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() &&
!dstRect.isEmpty()) {
@@ -281,10 +277,12 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch
// HWUI always draws 9-patches with linear filtering, regardless of the Paint.
const SkFilterMode filter = SkFilterMode::kLinear;
- applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
- mRecorder.drawImageLattice(image, lattice, dst.makeOffset(x, y), filter, p,
- bitmap.palette());
- });
+ applyLooper(
+ paint,
+ [&](const SkPaint& p) {
+ mRecorder.drawImageLattice(image, lattice, dst, filter, &p, bitmap.palette());
+ },
+ FilterForImage);
if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
mDisplayList->mMutableImages.push_back(image.get());
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 1e404b845084..ff03e0c5f6d6 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -87,22 +87,7 @@ private:
std::unique_ptr<SkiaDisplayList> mDisplayList;
StartReorderBarrierDrawable* mCurrentBarrier;
- template <typename Proc>
- void applyLooper(const Paint* paint, Proc proc) {
- SkPaint skp;
- BlurDrawLooper* looper = nullptr;
- if (paint) {
- skp = *filterBitmap(paint);
- looper = paint->getLooper();
- }
- if (looper) {
- looper->apply(skp, [&](SkPoint offset, const SkPaint& modifiedPaint) {
- proc(offset.fX, offset.fY, &modifiedPaint);
- });
- } else {
- proc(0, 0, &skp);
- }
- }
+ static void FilterForImage(SkPaint&);
/**
* A new SkiaDisplayList is created or recycled if available.
@@ -113,7 +98,7 @@ private:
*/
void initDisplayList(uirenderer::RenderNode* renderNode, int width, int height);
- PaintCoW&& filterBitmap(PaintCoW&& paint);
+ using INHERITED = SkiaCanvas;
};
} // namespace skiapipeline
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index b760db287bcb..f69ddacf7ca1 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -484,7 +484,8 @@ void CanvasContext::draw() {
// TODO(b/165985262): measure performance impact
const auto vsyncId = mCurrentFrameInfo->get(FrameInfoIndex::FrameTimelineVsyncId);
if (vsyncId != UiFrameInfoBuilder::INVALID_VSYNC_ID) {
- const auto inputEventId = mCurrentFrameInfo->get(FrameInfoIndex::NewestInputEvent);
+ const auto inputEventId =
+ static_cast<int32_t>(mCurrentFrameInfo->get(FrameInfoIndex::InputEventId));
native_window_set_frame_timeline_info(mNativeSurface->getNativeWindow(), vsyncId,
inputEventId);
}
@@ -591,7 +592,6 @@ void CanvasContext::draw() {
}
void CanvasContext::finishFrame(FrameInfo* frameInfo) {
-
// TODO (b/169858044): Consolidate this into a single call.
mJankTracker.finishFrame(*frameInfo);
mJankTracker.finishGpuDraw(*frameInfo);
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
index ab23448ab93f..1a3dbe7faaf6 100644
--- a/libs/hwui/tests/unit/TypefaceTests.cpp
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -33,7 +33,7 @@ namespace {
constexpr char kRobotoVariable[] = "/system/fonts/Roboto-Regular.ttf";
-constexpr char kRegularFont[] = "/system/fonts/NotoSerif-Regular.ttf";
+constexpr char kRegularFont[] = "/system/fonts/NotoSerif.ttf";
constexpr char kBoldFont[] = "/system/fonts/NotoSerif-Bold.ttf";
constexpr char kItalicFont[] = "/system/fonts/NotoSerif-Italic.ttf";
constexpr char kBoldItalicFont[] = "/system/fonts/NotoSerif-BoldItalic.ttf";
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index adf58da6a072..5e3966032a11 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -48,13 +48,13 @@ import android.os.ICancellationSignal;
*/
interface ILocationManager
{
- @nullable Location getLastLocation(String provider, in LastLocationRequest request, String packageName, String attributionTag);
- @nullable ICancellationSignal getCurrentLocation(String provider, in LocationRequest request, in ILocationCallback callback, String packageName, String attributionTag, String listenerId);
+ @nullable Location getLastLocation(String provider, in LastLocationRequest request, String packageName, @nullable String attributionTag);
+ @nullable ICancellationSignal getCurrentLocation(String provider, in LocationRequest request, in ILocationCallback callback, String packageName, @nullable String attributionTag, String listenerId);
- void registerLocationListener(String provider, in LocationRequest request, in ILocationListener listener, String packageName, String attributionTag, String listenerId);
+ void registerLocationListener(String provider, in LocationRequest request, in ILocationListener listener, String packageName, @nullable String attributionTag, String listenerId);
void unregisterLocationListener(in ILocationListener listener);
- void registerLocationPendingIntent(String provider, in LocationRequest request, in PendingIntent pendingIntent, String packageName, String attributionTag);
+ void registerLocationPendingIntent(String provider, in LocationRequest request, in PendingIntent pendingIntent, String packageName, @nullable String attributionTag);
void unregisterLocationPendingIntent(in PendingIntent pendingIntent);
void injectLocation(in Location location);
@@ -79,24 +79,24 @@ interface ILocationManager
@nullable List<GnssAntennaInfo> getGnssAntennaInfos();
- void registerGnssStatusCallback(in IGnssStatusListener callback, String packageName, @nullable String attributionTag);
+ void registerGnssStatusCallback(in IGnssStatusListener callback, String packageName, @nullable String attributionTag, String listenerId);
void unregisterGnssStatusCallback(in IGnssStatusListener callback);
- void registerGnssNmeaCallback(in IGnssNmeaListener callback, String packageName, @nullable String attributionTag);
+ void registerGnssNmeaCallback(in IGnssNmeaListener callback, String packageName, @nullable String attributionTag, String listenerId);
void unregisterGnssNmeaCallback(in IGnssNmeaListener callback);
- void addGnssMeasurementsListener(in GnssMeasurementRequest request, in IGnssMeasurementsListener listener, String packageName, @nullable String attributionTag);
+ void addGnssMeasurementsListener(in GnssMeasurementRequest request, in IGnssMeasurementsListener listener, String packageName, @nullable String attributionTag, String listenerId);
void removeGnssMeasurementsListener(in IGnssMeasurementsListener listener);
void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections);
- void addGnssNavigationMessageListener(in IGnssNavigationMessageListener listener, String packageName, @nullable String attributionTag);
+ void addGnssNavigationMessageListener(in IGnssNavigationMessageListener listener, String packageName, @nullable String attributionTag, String listenerId);
void removeGnssNavigationMessageListener(in IGnssNavigationMessageListener listener);
void addProviderRequestListener(in IProviderRequestListener listener);
void removeProviderRequestListener(in IProviderRequestListener listener);
int getGnssBatchSize();
- void startGnssBatch(long periodNanos, in ILocationListener listener, String packageName, @nullable String attributionTag, @nullable String listenerId);
+ void startGnssBatch(long periodNanos, in ILocationListener listener, String packageName, @nullable String attributionTag, String listenerId);
void flushGnssBatch();
void stopGnssBatch();
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index b7823400695d..dd5b6e6b4222 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -51,7 +51,7 @@ import android.content.pm.PackageManager;
import android.location.provider.IProviderRequestListener;
import android.location.provider.ProviderProperties;
import android.location.provider.ProviderRequest;
-import android.location.provider.ProviderRequest.Listener;
+import android.location.provider.ProviderRequest.ChangedListener;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -2779,33 +2779,32 @@ public class LocationManager {
}
/**
- * Registers a {@link ProviderRequest.Listener} to all providers.
+ * Adds a {@link ProviderRequest.ChangedListener} for listening to all providers'
+ * {@link ProviderRequest} changed events.
*
* @param executor the executor that the callback runs on
* @param listener the listener to register
- * @return {@code true} always
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
- public boolean registerProviderRequestListener(
+ public void addProviderRequestChangedListener(
@NonNull @CallbackExecutor Executor executor,
- @NonNull Listener listener) {
+ @NonNull ChangedListener listener) {
ProviderRequestLazyLoader.sProviderRequestListeners.addListener(listener,
new ProviderRequestTransport(executor, listener));
- return true;
}
/**
- * Unregisters a {@link ProviderRequest.Listener}.
+ * Removes a {@link ProviderRequest.ChangedListener} that has been added.
*
* @param listener the listener to remove.
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
- public void unregisterProviderRequestListener(
- @NonNull Listener listener) {
+ public void removeProviderRequestChangedListener(
+ @NonNull ProviderRequest.ChangedListener listener) {
ProviderRequestLazyLoader.sProviderRequestListeners.removeListener(listener);
}
@@ -2926,7 +2925,8 @@ public class LocationManager {
protected void registerTransport(GnssStatusTransport transport)
throws RemoteException {
getService().registerGnssStatusCallback(transport, transport.getPackage(),
- transport.getAttributionTag());
+ transport.getAttributionTag(),
+ AppOpsManager.toReceiverId(transport.getListener()));
}
@Override
@@ -2947,7 +2947,8 @@ public class LocationManager {
protected void registerTransport(GnssNmeaTransport transport)
throws RemoteException {
getService().registerGnssNmeaCallback(transport, transport.getPackage(),
- transport.getAttributionTag());
+ transport.getAttributionTag(),
+ AppOpsManager.toReceiverId(transport.getListener()));
}
@Override
@@ -2968,7 +2969,8 @@ public class LocationManager {
protected void registerTransport(GnssMeasurementsTransport transport)
throws RemoteException {
getService().addGnssMeasurementsListener(transport.getRequest(), transport,
- transport.getPackage(), transport.getAttributionTag());
+ transport.getPackage(), transport.getAttributionTag(),
+ AppOpsManager.toReceiverId(transport.getListener()));
}
@Override
@@ -3008,7 +3010,8 @@ public class LocationManager {
protected void registerTransport(GnssNavigationTransport transport)
throws RemoteException {
getService().addGnssNavigationMessageListener(transport,
- transport.getPackage(), transport.getAttributionTag());
+ transport.getPackage(), transport.getAttributionTag(),
+ AppOpsManager.toReceiverId(transport.getListener()));
}
@Override
@@ -3442,13 +3445,13 @@ public class LocationManager {
}
private static class ProviderRequestTransport extends IProviderRequestListener.Stub
- implements ListenerTransport<ProviderRequest.Listener> {
+ implements ListenerTransport<ChangedListener> {
private final Executor mExecutor;
- private volatile @Nullable ProviderRequest.Listener mListener;
+ private volatile @Nullable ProviderRequest.ChangedListener mListener;
- ProviderRequestTransport(Executor executor, ProviderRequest.Listener listener) {
+ ProviderRequestTransport(Executor executor, ChangedListener listener) {
Preconditions.checkArgument(executor != null, "invalid null executor");
Preconditions.checkArgument(listener != null, "invalid null callback");
mExecutor = executor;
@@ -3461,7 +3464,7 @@ public class LocationManager {
}
@Override
- public @Nullable ProviderRequest.Listener getListener() {
+ public @Nullable ProviderRequest.ChangedListener getListener() {
return mListener;
}
diff --git a/location/java/android/location/provider/ProviderRequest.java b/location/java/android/location/provider/ProviderRequest.java
index b6ec32309b08..b72d36519e72 100644
--- a/location/java/android/location/provider/ProviderRequest.java
+++ b/location/java/android/location/provider/ProviderRequest.java
@@ -56,10 +56,13 @@ public final class ProviderRequest implements Parcelable {
/**
* Listener to be invoked when a new request is set to the provider.
*/
- public interface Listener {
+ public interface ChangedListener {
/**
* Invoked when a new request is set.
+ *
+ * @param provider the location provider associated with the request
+ * @param request the new {@link ProviderRequest}
*/
void onProviderRequestChanged(@NonNull String provider, @NonNull ProviderRequest request);
}
diff --git a/location/java/android/location/util/identity/CallerIdentity.java b/location/java/android/location/util/identity/CallerIdentity.java
index 0bb7dbb71ae8..85a083ee84bc 100644
--- a/location/java/android/location/util/identity/CallerIdentity.java
+++ b/location/java/android/location/util/identity/CallerIdentity.java
@@ -42,7 +42,16 @@ public final class CallerIdentity {
@VisibleForTesting
public static CallerIdentity forTest(int uid, int pid, String packageName,
@Nullable String attributionTag) {
- return new CallerIdentity(uid, pid, packageName, attributionTag, null);
+ return forTest(uid, pid, packageName, attributionTag, null);
+ }
+
+ /**
+ * Construct a CallerIdentity for test purposes.
+ */
+ @VisibleForTesting
+ public static CallerIdentity forTest(int uid, int pid, String packageName,
+ @Nullable String attributionTag, @Nullable String listenerId) {
+ return new CallerIdentity(uid, pid, packageName, attributionTag, listenerId);
}
/**
@@ -145,7 +154,10 @@ public final class CallerIdentity {
return mAttributionTag;
}
- /** The calling listener id. */
+ /**
+ * The calling listener id. A null listener id will match any other listener id for the purposes
+ * of {@link #equals(Object)}.
+ */
public String getListenerId() {
return mListenerId;
}
@@ -168,6 +180,17 @@ public final class CallerIdentity {
}
}
+ /**
+ * Returns a CallerIdentity corrosponding to this CallerIdentity but with a null listener id.
+ */
+ public CallerIdentity stripListenerId() {
+ if (mListenerId == null) {
+ return this;
+ } else {
+ return new CallerIdentity(mUid, mPid, mPackageName, mAttributionTag, null);
+ }
+ }
+
@Override
public String toString() {
int length = 10 + mPackageName.length();
@@ -201,15 +224,12 @@ public final class CallerIdentity {
return false;
}
CallerIdentity that = (CallerIdentity) o;
- return equalsIgnoringListenerId(that) && Objects.equals(mListenerId, that.mListenerId);
- }
-
- public boolean equalsIgnoringListenerId(CallerIdentity that) {
- return that != null
- && mUid == that.mUid
+ return mUid == that.mUid
&& mPid == that.mPid
&& mPackageName.equals(that.mPackageName)
- && Objects.equals(mAttributionTag, that.mAttributionTag);
+ && Objects.equals(mAttributionTag, that.mAttributionTag)
+ && (mListenerId == null || that.mListenerId == null || mListenerId.equals(
+ that.mListenerId));
}
@Override
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 44f8385b715e..9ab4aac891e5 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -131,7 +131,59 @@ public class ImageWriter implements AutoCloseable {
*/
public static @NonNull ImageWriter newInstance(@NonNull Surface surface,
@IntRange(from = 1) int maxImages) {
- return new ImageWriter(surface, maxImages, ImageFormat.UNKNOWN);
+ return new ImageWriter(surface, maxImages, ImageFormat.UNKNOWN, -1 /*width*/,
+ -1 /*height*/);
+ }
+
+ /**
+ * <p>
+ * Create a new ImageWriter with given number of max Images, format and producer dimension.
+ * </p>
+ * <p>
+ * The {@code maxImages} parameter determines the maximum number of
+ * {@link Image} objects that can be be dequeued from the
+ * {@code ImageWriter} simultaneously. Requesting more buffers will use up
+ * more memory, so it is important to use only the minimum number necessary.
+ * </p>
+ * <p>
+ * The format specifies the image format of this ImageWriter. The format
+ * from the {@code surface} will be overridden with this format. For example,
+ * if the surface is obtained from a {@link android.graphics.SurfaceTexture}, the default
+ * format may be {@link PixelFormat#RGBA_8888}. If the application creates an ImageWriter
+ * with this surface and {@link ImageFormat#PRIVATE}, this ImageWriter will be able to operate
+ * with {@link ImageFormat#PRIVATE} Images.
+ * </p>
+ * <p>
+ * Note that the consumer end-point may or may not be able to support Images with different
+ * format, for such case, the application should only use this method if the consumer is able
+ * to consume such images.
+ * </p>
+ * <p> The input Image size can also be set by the client. </p>
+ *
+ * @param surface The destination Surface this writer produces Image data
+ * into.
+ * @param maxImages The maximum number of Images the user will want to
+ * access simultaneously for producing Image data. This should be
+ * as small as possible to limit memory use. Once maxImages
+ * Images are dequeued by the user, one of them has to be queued
+ * back before a new Image can be dequeued for access via
+ * {@link #dequeueInputImage()}.
+ * @param format The format of this ImageWriter. It can be any valid format specified by
+ * {@link ImageFormat} or {@link PixelFormat}.
+ *
+ * @param width Input size width.
+ * @param height Input size height.
+ *
+ * @return a new ImageWriter instance.
+ *
+ * @hide
+ */
+ public static @NonNull ImageWriter newInstance(@NonNull Surface surface,
+ @IntRange(from = 1) int maxImages, @Format int format, int width, int height) {
+ if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
+ throw new IllegalArgumentException("Invalid format is specified: " + format);
+ }
+ return new ImageWriter(surface, maxImages, format, width, height);
}
/**
@@ -180,13 +232,13 @@ public class ImageWriter implements AutoCloseable {
if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
throw new IllegalArgumentException("Invalid format is specified: " + format);
}
- return new ImageWriter(surface, maxImages, format);
+ return new ImageWriter(surface, maxImages, format, -1 /*width*/, -1 /*height*/);
}
/**
* @hide
*/
- protected ImageWriter(Surface surface, int maxImages, int format) {
+ protected ImageWriter(Surface surface, int maxImages, int format, int width, int height) {
if (surface == null || maxImages < 1) {
throw new IllegalArgumentException("Illegal input argument: surface " + surface
+ ", maxImages: " + maxImages);
@@ -196,7 +248,8 @@ public class ImageWriter implements AutoCloseable {
// Note that the underlying BufferQueue is working in synchronous mode
// to avoid dropping any buffers.
- mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, format);
+ mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, format, width,
+ height);
// nativeInit internally overrides UNKNOWN format. So does surface format query after
// nativeInit and before getEstimatedNativeAllocBytes().
@@ -919,7 +972,7 @@ public class ImageWriter implements AutoCloseable {
// Native implemented ImageWriter methods.
private synchronized native long nativeInit(Object weakSelf, Surface surface, int maxImgs,
- int format);
+ int format, int width, int height);
private synchronized native void nativeClose(long nativeCtx);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index c51c9dd06c24..f3cee17ab238 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -19,6 +19,7 @@ package android.media;
import static android.Manifest.permission.BIND_IMS_SERVICE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -91,6 +92,7 @@ import java.util.Scanner;
import java.util.Set;
import java.util.UUID;
import java.util.Vector;
+import java.util.concurrent.Executor;
/**
@@ -2172,7 +2174,7 @@ public class MediaPlayer extends PlayerBase
mOnVideoSizeChangedListener = null;
mOnTimedTextListener = null;
mOnRtpRxNoticeListener = null;
- mOnRtpRxNoticeHandler = null;
+ mOnRtpRxNoticeExecutor = null;
synchronized (mTimeProviderLock) {
if (mTimeProvider != null) {
mTimeProvider.close();
@@ -3711,7 +3713,6 @@ public class MediaPlayer extends PlayerBase
case MEDIA_RTP_RX_NOTICE:
final OnRtpRxNoticeListener rtpRxNoticeListener = mOnRtpRxNoticeListener;
- final Handler rtpRxNoticeHandler = mOnRtpRxNoticeHandler;
if (rtpRxNoticeListener == null) {
return;
}
@@ -3730,14 +3731,9 @@ public class MediaPlayer extends PlayerBase
} finally {
parcel.recycle();
}
- if (rtpRxNoticeHandler == null) {
- rtpRxNoticeListener.onRtpRxNotice(mMediaPlayer, noticeType, data);
- } else {
- rtpRxNoticeHandler.post(
- () ->
- rtpRxNoticeListener
- .onRtpRxNotice(mMediaPlayer, noticeType, data));
- }
+ mOnRtpRxNoticeExecutor.execute(() ->
+ rtpRxNoticeListener
+ .onRtpRxNotice(mMediaPlayer, noticeType, data));
}
return;
@@ -4305,28 +4301,26 @@ public class MediaPlayer extends PlayerBase
*
* @see OnRtpRxNoticeListener
*
- * @param listener the listener called after a notice from RTP Rx
- * @param handler the {@link Handler} that receives RTP Tx events. If null is passed,
- * notifications will be posted on the thread that created this MediaPlayer
- * instance. If the creating thread does not have a {@link Looper}, then
- * notifications will be posted on the main thread.
+ * @param listener the listener called after a notice from RTP Rx.
+ * @param executor the {@link Executor} on which to post RTP Tx events.
* @hide
*/
@SystemApi
@RequiresPermission(BIND_IMS_SERVICE)
public void setOnRtpRxNoticeListener(
@NonNull Context context,
- @NonNull OnRtpRxNoticeListener listener, @Nullable Handler handler) {
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnRtpRxNoticeListener listener) {
Objects.requireNonNull(context);
Preconditions.checkArgument(
context.checkSelfPermission(BIND_IMS_SERVICE) == PERMISSION_GRANTED,
BIND_IMS_SERVICE + " permission not granted.");
mOnRtpRxNoticeListener = Objects.requireNonNull(listener);
- mOnRtpRxNoticeHandler = handler;
+ mOnRtpRxNoticeExecutor = Objects.requireNonNull(executor);
}
private OnRtpRxNoticeListener mOnRtpRxNoticeListener;
- private Handler mOnRtpRxNoticeHandler;
+ private Executor mOnRtpRxNoticeExecutor;
/**
* Register a callback to be invoked when a selected track has timed metadata available.
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 8de5e42e93b2..aa0f7fdd70d5 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -34,6 +34,7 @@ import android.media.Session2Token;
import android.media.VolumeProvider;
import android.os.Bundle;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
@@ -321,7 +322,7 @@ public final class MediaSessionManager {
@NonNull OnActiveSessionsChangedListener sessionListener,
@Nullable ComponentName notificationListener, @Nullable Handler handler) {
addOnActiveSessionsChangedListener(sessionListener, notificationListener,
- UserHandle.myUserId(), handler);
+ UserHandle.myUserId(), handler == null ? null : new HandlerExecutor(handler));
}
/**
@@ -337,38 +338,40 @@ public final class MediaSessionManager {
* {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to
* add listeners for user ids that do not belong to current process.
*
- * @param sessionListener The listener to add.
* @param notificationListener The enabled notification listener component. May be null.
* @param userHandle The user handle to listen for changes on.
- * @param handler The handler to post updates on.
+ * @param executor The executor on which the listener should be invoked
+ * @param sessionListener The listener to add.
* @hide
*/
- @SuppressLint({"ExecutorRegistration", "SamShouldBeLast", "UserHandle"})
+ @SuppressLint("UserHandle")
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void addOnActiveSessionsChangedListener(
- @NonNull OnActiveSessionsChangedListener sessionListener,
- @Nullable ComponentName notificationListener, @NonNull UserHandle userHandle,
- @Nullable Handler handler) {
+ @Nullable ComponentName notificationListener,
+ @NonNull UserHandle userHandle, @NonNull Executor executor,
+ @NonNull OnActiveSessionsChangedListener sessionListener) {
Objects.requireNonNull(userHandle, "userHandle shouldn't be null");
+ Objects.requireNonNull(executor, "executor shouldn't be null");
addOnActiveSessionsChangedListener(sessionListener, notificationListener,
- userHandle.getIdentifier(), handler);
+ userHandle.getIdentifier(), executor);
}
private void addOnActiveSessionsChangedListener(
@NonNull OnActiveSessionsChangedListener sessionListener,
@Nullable ComponentName notificationListener, int userId,
- @Nullable Handler handler) {
+ @Nullable Executor executor) {
Objects.requireNonNull(sessionListener, "sessionListener shouldn't be null");
- if (handler == null) {
- handler = new Handler();
+ if (executor == null) {
+ executor = new HandlerExecutor(new Handler());
}
+
synchronized (mLock) {
if (mListeners.get(sessionListener) != null) {
Log.w(TAG, "Attempted to add session listener twice, ignoring.");
return;
}
SessionsChangedWrapper wrapper = new SessionsChangedWrapper(mContext, sessionListener,
- handler);
+ executor);
try {
mService.addSessionsListener(wrapper.mStub, notificationListener, userId);
mListeners.put(sessionListener, wrapper);
@@ -412,7 +415,8 @@ public final class MediaSessionManager {
*/
public void addOnSession2TokensChangedListener(
@NonNull OnSession2TokensChangedListener listener) {
- addOnSession2TokensChangedListener(UserHandle.myUserId(), listener, new Handler());
+ addOnSession2TokensChangedListener(UserHandle.myUserId(), listener,
+ new HandlerExecutor(new Handler()));
}
/**
@@ -428,7 +432,9 @@ public final class MediaSessionManager {
*/
public void addOnSession2TokensChangedListener(
@NonNull OnSession2TokensChangedListener listener, @NonNull Handler handler) {
- addOnSession2TokensChangedListener(UserHandle.myUserId(), listener, handler);
+ Objects.requireNonNull(handler, "handler shouldn't be null");
+ addOnSession2TokensChangedListener(UserHandle.myUserId(), listener,
+ new HandlerExecutor(handler));
}
/**
@@ -445,20 +451,19 @@ public final class MediaSessionManager {
*
* @param userHandle The userHandle to listen for changes on
* @param listener The listener to add
- * @param handler The handler to call listener on. If {@code null}, calling thread's looper will
- * be used.
+ * @param executor The executor on which the listener should be invoked
* @hide
*/
@SuppressLint("UserHandle")
public void addOnSession2TokensChangedListener(@NonNull UserHandle userHandle,
- @NonNull OnSession2TokensChangedListener listener, @NonNull Handler handler) {
+ @NonNull OnSession2TokensChangedListener listener, @NonNull Executor executor) {
Objects.requireNonNull(userHandle, "userHandle shouldn't be null");
- addOnSession2TokensChangedListener(userHandle.getIdentifier(), listener, handler);
+ Objects.requireNonNull(executor, "executor shouldn't be null");
+ addOnSession2TokensChangedListener(userHandle.getIdentifier(), listener, executor);
}
private void addOnSession2TokensChangedListener(int userId,
- OnSession2TokensChangedListener listener, Handler handler) {
- Objects.requireNonNull(handler, "handler shouldn't be null");
+ OnSession2TokensChangedListener listener, Executor executor) {
Objects.requireNonNull(listener, "listener shouldn't be null");
synchronized (mLock) {
if (mSession2TokensListeners.get(listener) != null) {
@@ -466,7 +471,7 @@ public final class MediaSessionManager {
return;
}
Session2TokensChangedWrapper wrapper =
- new Session2TokensChangedWrapper(listener, handler);
+ new Session2TokensChangedWrapper(listener, executor);
try {
mService.addSession2TokensListener(wrapper.getStub(), userId);
mSession2TokensListeners.put(listener, wrapper);
@@ -847,7 +852,7 @@ public final class MediaSessionManager {
/**
* Add a {@link OnMediaKeyEventDispatchedListener}.
*
- * @param executor The executor on which the callback should be invoked
+ * @param executor The executor on which the listener should be invoked
* @param listener A {@link OnMediaKeyEventDispatchedListener}.
* @hide
*/
@@ -898,7 +903,7 @@ public final class MediaSessionManager {
/**
* Add a {@link OnMediaKeyEventDispatchedListener}.
*
- * @param executor The executor on which the callback should be invoked
+ * @param executor The executor on which the listener should be invoked
* @param listener A {@link OnMediaKeyEventSessionChangedListener}.
* @hide
*/
@@ -1257,62 +1262,61 @@ public final class MediaSessionManager {
private static final class SessionsChangedWrapper {
private Context mContext;
private OnActiveSessionsChangedListener mListener;
- private Handler mHandler;
+ private Executor mExecutor;
public SessionsChangedWrapper(Context context, OnActiveSessionsChangedListener listener,
- Handler handler) {
+ Executor executor) {
mContext = context;
mListener = listener;
- mHandler = handler;
+ mExecutor = executor;
}
private final IActiveSessionsListener.Stub mStub = new IActiveSessionsListener.Stub() {
@Override
public void onActiveSessionsChanged(final List<MediaSession.Token> tokens) {
- final Handler handler = mHandler;
- if (handler != null) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- final Context context = mContext;
- if (context != null) {
- ArrayList<MediaController> controllers = new ArrayList<>();
- int size = tokens.size();
- for (int i = 0; i < size; i++) {
- controllers.add(new MediaController(context, tokens.get(i)));
- }
- final OnActiveSessionsChangedListener listener = mListener;
- if (listener != null) {
- listener.onActiveSessionsChanged(controllers);
- }
- }
- }
- });
+ if (mExecutor != null) {
+ final Executor executor = mExecutor;
+ executor.execute(() -> callOnActiveSessionsChangedListener(tokens));
}
}
};
+ private void callOnActiveSessionsChangedListener(final List<MediaSession.Token> tokens) {
+ final Context context = mContext;
+ if (context != null) {
+ ArrayList<MediaController> controllers = new ArrayList<>();
+ int size = tokens.size();
+ for (int i = 0; i < size; i++) {
+ controllers.add(new MediaController(context, tokens.get(i)));
+ }
+ final OnActiveSessionsChangedListener listener = mListener;
+ if (listener != null) {
+ listener.onActiveSessionsChanged(controllers);
+ }
+ }
+ }
+
private void release() {
mListener = null;
mContext = null;
- mHandler = null;
+ mExecutor = null;
}
}
private static final class Session2TokensChangedWrapper {
private final OnSession2TokensChangedListener mListener;
- private final Handler mHandler;
+ private final Executor mExecutor;
private final ISession2TokensListener.Stub mStub =
new ISession2TokensListener.Stub() {
@Override
public void onSession2TokensChanged(final List<Session2Token> tokens) {
- mHandler.post(() -> mListener.onSession2TokensChanged(tokens));
+ mExecutor.execute(() -> mListener.onSession2TokensChanged(tokens));
}
};
- Session2TokensChangedWrapper(OnSession2TokensChangedListener listener, Handler handler) {
+ Session2TokensChangedWrapper(OnSession2TokensChangedListener listener, Executor executor) {
mListener = listener;
- mHandler = (handler == null) ? new Handler() : new Handler(handler.getLooper());
+ mExecutor = executor;
}
public ISession2TokensListener.Stub getStub() {
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 5d959a3930f4..b291ac95bf4f 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -364,7 +364,7 @@ static void ImageWriter_classInit(JNIEnv* env, jclass clazz) {
}
static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobject jsurface,
- jint maxImages, jint userFormat) {
+ jint maxImages, jint userFormat, jint userWidth, jint userHeight) {
status_t res;
ALOGV("%s: maxImages:%d", __FUNCTION__, maxImages);
@@ -405,20 +405,38 @@ static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobje
// Get the dimension and format of the producer.
sp<ANativeWindow> anw = producer;
int32_t width, height, surfaceFormat;
- if ((res = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, &width)) != OK) {
- ALOGE("%s: Query Surface width failed: %s (%d)", __FUNCTION__, strerror(-res), res);
- jniThrowRuntimeException(env, "Failed to query Surface width");
- return 0;
+ if (userWidth < 0) {
+ if ((res = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, &width)) != OK) {
+ ALOGE("%s: Query Surface width failed: %s (%d)", __FUNCTION__, strerror(-res), res);
+ jniThrowRuntimeException(env, "Failed to query Surface width");
+ return 0;
+ }
+ } else {
+ width = userWidth;
}
+
ctx->setBufferWidth(width);
- if ((res = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, &height)) != OK) {
- ALOGE("%s: Query Surface height failed: %s (%d)", __FUNCTION__, strerror(-res), res);
- jniThrowRuntimeException(env, "Failed to query Surface height");
- return 0;
+ if (userHeight < 0) {
+ if ((res = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, &height)) != OK) {
+ ALOGE("%s: Query Surface height failed: %s (%d)", __FUNCTION__, strerror(-res), res);
+ jniThrowRuntimeException(env, "Failed to query Surface height");
+ return 0;
+ }
+ } else {
+ height = userHeight;
}
ctx->setBufferHeight(height);
+ if ((userWidth > 0) && (userHeight > 0)) {
+ res = native_window_set_buffers_user_dimensions(anw.get(), userWidth, userHeight);
+ if (res != OK) {
+ ALOGE("%s: Set buffer dimensions failed: %s (%d)", __FUNCTION__, strerror(-res), res);
+ jniThrowRuntimeException(env, "Set buffer dimensions failed");
+ return 0;
+ }
+ }
+
// Query surface format if no valid user format is specified, otherwise, override surface format
// with user format.
if (userFormat == IMAGE_FORMAT_UNKNOWN) {
@@ -1045,7 +1063,7 @@ static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
static JNINativeMethod gImageWriterMethods[] = {
{"nativeClassInit", "()V", (void*)ImageWriter_classInit },
- {"nativeInit", "(Ljava/lang/Object;Landroid/view/Surface;II)J",
+ {"nativeInit", "(Ljava/lang/Object;Landroid/view/Surface;IIII)J",
(void*)ImageWriter_init },
{"nativeClose", "(J)V", (void*)ImageWriter_close },
{"nativeAttachAndQueueImage", "(JJIJIIIIII)I", (void*)ImageWriter_attachAndQueueImage },
diff --git a/media/jni/android_media_JetPlayer.cpp b/media/jni/android_media_JetPlayer.cpp
index 481f80b278f8..10a5b586c2b9 100644
--- a/media/jni/android_media_JetPlayer.cpp
+++ b/media/jni/android_media_JetPlayer.cpp
@@ -43,12 +43,34 @@ struct fields_t {
jfieldID nativePlayerInJavaObj; // stores in Java the native JetPlayer object
};
-static fields_t javaJetPlayerFields;
+static fields_t javaJetPlayerFields {};
+#define JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME "mNativePlayerInJavaObj"
+#define JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME "postEventFromNative"
+
+static void initializeJavaIDs(JNIEnv* env) {
+ static std::once_flag sJniInitialized;
+
+ std::call_once(sJniInitialized, [](JNIEnv* env) {
+ // Get the JetPlayer java class
+ jclass jetPlayerClass = FindClassOrDie(env, kClassPathName);
+ javaJetPlayerFields.jetClass = MakeGlobalRefOrDie(env, jetPlayerClass);
+
+ // Get the mNativePlayerInJavaObj variable field
+ javaJetPlayerFields.nativePlayerInJavaObj =
+ GetFieldIDOrDie(env, jetPlayerClass, JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME, "J");
+
+ // Get the callback to post events from this native code to Java
+ javaJetPlayerFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
+ javaJetPlayerFields.jetClass, JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME,
+ "(Ljava/lang/Object;III)V");
+ }, env);
+}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
+
/*
* This function is called from JetPlayer instance's render thread
*/
@@ -79,6 +101,8 @@ static jboolean
android_media_JetPlayer_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jint maxTracks, jint trackBufferSize)
{
+ initializeJavaIDs(env);
+
//ALOGV("android_media_JetPlayer_setup(): entering.");
JetPlayer* lpJet = new JetPlayer(env->NewGlobalRef(weak_this), maxTracks, trackBufferSize);
@@ -511,28 +535,9 @@ static const JNINativeMethod gMethods[] = {
{"native_clearQueue", "()Z", (void *)android_media_JetPlayer_clearQueue},
};
-#define JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME "mNativePlayerInJavaObj"
-#define JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME "postEventFromNative"
int register_android_media_JetPlayer(JNIEnv *env)
{
- javaJetPlayerFields.jetClass = NULL;
- javaJetPlayerFields.postNativeEventInJava = NULL;
- javaJetPlayerFields.nativePlayerInJavaObj = NULL;
-
- // Get the JetPlayer java class
- jclass jetPlayerClass = FindClassOrDie(env, kClassPathName);
- javaJetPlayerFields.jetClass = MakeGlobalRefOrDie(env, jetPlayerClass);
-
- // Get the mNativePlayerInJavaObj variable field
- javaJetPlayerFields.nativePlayerInJavaObj = GetFieldIDOrDie(env,
- jetPlayerClass, JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME, "J");
-
- // Get the callback to post events from this native code to Java
- javaJetPlayerFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
- javaJetPlayerFields.jetClass, JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME,
- "(Ljava/lang/Object;III)V");
-
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 71c86cc7d42d..1870a939f0dc 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -61,6 +61,7 @@
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/PersistentSurface.h>
+#include <mediadrm/DrmUtils.h>
#include <mediadrm/ICrypto.h>
#include <private/android/AHardwareBufferHelpers.h>
@@ -312,6 +313,7 @@ status_t JMediaCodec::configure(
mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))
&& !(flags & CONFIGURE_FLAG_ENCODE);
mHasCryptoOrDescrambler = (crypto != nullptr) || (descrambler != nullptr);
+ mCrypto = crypto;
return mCodec->configure(
format, mSurfaceTextureClient, crypto, descrambler, flags);
@@ -1103,6 +1105,8 @@ void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
}
}
+jint MediaErrorToJavaError(status_t err);
+
} // namespace android
////////////////////////////////////////////////////////////////////////////////
@@ -1150,7 +1154,8 @@ static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, c
env->Throw(exception);
}
-static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
+static void throwCryptoException(JNIEnv *env, status_t err, const char *msg,
+ const sp<ICrypto> &crypto) {
ScopedLocalRef<jclass> clazz(
env, env->FindClass("android/media/MediaCodec$CryptoException"));
CHECK(clazz.get() != NULL);
@@ -1159,7 +1164,7 @@ static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
CHECK(constructID != NULL);
- const char *defaultMsg = "Unknown Error";
+ std::string defaultMsg = "Unknown Error";
/* translate OS errors to Java API CryptoException errorCodes (which are positive) */
switch (err) {
@@ -1199,11 +1204,17 @@ static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
err = gCryptoErrorCodes.cryptoErrorLostState;
defaultMsg = "Session state was lost, open a new session and retry";
break;
- default: /* Other negative DRM error codes go out as is. */
+ default: /* Other negative DRM error codes go out best-effort. */
+ err = MediaErrorToJavaError(err);
+ defaultMsg = StrCryptoError(err);
break;
}
- jstring msgObj = env->NewStringUTF(msg != NULL ? msg : defaultMsg);
+ std::string msgStr(msg != NULL ? msg : defaultMsg.c_str());
+ if (crypto != NULL) {
+ msgStr = DrmUtils::GetExceptionMessage(err, msgStr.c_str(), crypto);
+ }
+ jstring msgObj = env->NewStringUTF(msgStr.c_str());
jthrowable exception =
(jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
@@ -1213,7 +1224,7 @@ static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
static jint throwExceptionAsNecessary(
JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
- const char *msg = NULL) {
+ const char *msg = NULL, const sp<ICrypto>& crypto = NULL) {
switch (err) {
case OK:
return 0;
@@ -1237,7 +1248,7 @@ static jint throwExceptionAsNecessary(
default:
if (isCryptoError(err)) {
- throwCryptoException(env, err, msg);
+ throwCryptoException(env, err, msg, crypto);
return 0;
}
throwCodecException(env, err, actionCode, msg);
@@ -1899,7 +1910,8 @@ static void android_media_MediaCodec_queueSecureInputBuffer(
subSamples = NULL;
throwExceptionAsNecessary(
- env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
+ env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str(),
+ codec->getCrypto());
}
static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index a58f9a74b563..f16bcf3c88e4 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -164,6 +164,8 @@ struct JMediaCodec : public AHandler {
bool hasCryptoOrDescrambler() { return mHasCryptoOrDescrambler; }
+ const sp<ICrypto> &getCrypto() { return mCrypto; }
+
protected:
virtual ~JMediaCodec();
@@ -193,6 +195,8 @@ private:
status_t mInitStatus;
+ sp<ICrypto> mCrypto;
+
template <typename T>
status_t createByteBufferFromABuffer(
JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp
index 517672ee6127..f491be884b2f 100644
--- a/media/jni/android_media_MediaCrypto.cpp
+++ b/media/jni/android_media_MediaCrypto.cpp
@@ -202,10 +202,11 @@ static void android_media_MediaCrypto_native_setup(
uuid = NULL;
if (err != OK) {
- jniThrowException(
+ std::string strerr(StrCryptoError(err));
+ jniThrowExceptionFmt(
env,
"android/media/MediaCryptoException",
- "Failed to instantiate crypto object.");
+ "Failed to instantiate crypto object: %s", strerr.c_str());
return;
}
@@ -295,7 +296,8 @@ static void android_media_MediaCrypto_setMediaDrmSession(
} else if (err == NO_INIT) {
msg += ": crypto plugin not initialized";
} else {
- msg.appendFormat(": general failure (%d)", err);
+ std::string strerr(StrCryptoError(err));
+ msg.appendFormat(": general failure (%s)", strerr.c_str());
}
jniThrowException(env, "android/media/MediaCryptoException", msg.string());
}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index eee9f1e08131..3669bf44c42a 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -217,23 +217,34 @@ namespace android {
void LnbClientCallbackImpl::onEvent(const LnbEventType lnbEventType) {
ALOGD("LnbClientCallbackImpl::onEvent, type=%d", lnbEventType);
JNIEnv *env = AndroidRuntime::getJNIEnv();
- env->CallVoidMethod(
- mLnbObj,
- gFields.onLnbEventID,
- (jint)lnbEventType);
+ jobject lnb(env->NewLocalRef(mLnbObj));
+ if (!env->IsSameObject(lnb, nullptr)) {
+ env->CallVoidMethod(
+ lnb,
+ gFields.onLnbEventID,
+ (jint)lnbEventType);
+ } else {
+ ALOGE("LnbClientCallbackImpl::onEvent:"
+ "Lnb object has been freed. Ignoring callback.");
+ }
}
void LnbClientCallbackImpl::onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) {
ALOGD("LnbClientCallbackImpl::onDiseqcMessage");
JNIEnv *env = AndroidRuntime::getJNIEnv();
- jbyteArray array = env->NewByteArray(diseqcMessage.size());
- env->SetByteArrayRegion(
- array, 0, diseqcMessage.size(), reinterpret_cast<jbyte*>(diseqcMessage[0]));
-
- env->CallVoidMethod(
- mLnbObj,
- gFields.onLnbDiseqcMessageID,
- array);
+ jobject lnb(env->NewLocalRef(mLnbObj));
+ if (!env->IsSameObject(lnb, nullptr)) {
+ jbyteArray array = env->NewByteArray(diseqcMessage.size());
+ env->SetByteArrayRegion(
+ array, 0, diseqcMessage.size(), reinterpret_cast<jbyte*>(diseqcMessage[0]));
+ env->CallVoidMethod(
+ lnb,
+ gFields.onLnbDiseqcMessageID,
+ array);
+ } else {
+ ALOGE("LnbClientCallbackImpl::onDiseqcMessage:"
+ "Lnb object has been freed. Ignoring callback.");
+ }
}
void LnbClientCallbackImpl::setLnb(jweak lnbObj) {
@@ -254,19 +265,31 @@ LnbClientCallbackImpl::~LnbClientCallbackImpl() {
void DvrClientCallbackImpl::onRecordStatus(RecordStatus status) {
ALOGD("DvrClientCallbackImpl::onRecordStatus");
JNIEnv *env = AndroidRuntime::getJNIEnv();
- env->CallVoidMethod(
- mDvrObj,
- gFields.onDvrRecordStatusID,
- (jint) status);
+ jobject dvr(env->NewLocalRef(mDvrObj));
+ if (!env->IsSameObject(dvr, nullptr)) {
+ env->CallVoidMethod(
+ dvr,
+ gFields.onDvrRecordStatusID,
+ (jint) status);
+ } else {
+ ALOGE("DvrClientCallbackImpl::onRecordStatus:"
+ "Dvr object has been freed. Ignoring callback.");
+ }
}
void DvrClientCallbackImpl::onPlaybackStatus(PlaybackStatus status) {
ALOGD("DvrClientCallbackImpl::onPlaybackStatus");
JNIEnv *env = AndroidRuntime::getJNIEnv();
- env->CallVoidMethod(
- mDvrObj,
- gFields.onDvrPlaybackStatusID,
- (jint) status);
+ jobject dvr(env->NewLocalRef(mDvrObj));
+ if (!env->IsSameObject(dvr, nullptr)) {
+ env->CallVoidMethod(
+ dvr,
+ gFields.onDvrPlaybackStatusID,
+ (jint) status);
+ } else {
+ ALOGE("DvrClientCallbackImpl::onPlaybackStatus:"
+ "Dvr object has been freed. Ignoring callback.");
+ }
}
void DvrClientCallbackImpl::setDvr(jweak dvrObj) {
@@ -810,10 +833,16 @@ void FilterClientCallbackImpl::onFilterEvent_1_1(const DemuxFilterEvent& filterE
}
}
}
- env->CallVoidMethod(
- mFilterObj,
- gFields.onFilterEventID,
- array);
+ jobject filter(env->NewLocalRef(mFilterObj));
+ if (!env->IsSameObject(filter, nullptr)) {
+ env->CallVoidMethod(
+ filter,
+ gFields.onFilterEventID,
+ array);
+ } else {
+ ALOGE("FilterClientCallbackImpl::onFilterEvent_1_1:"
+ "Filter object has been freed. Ignoring callback.");
+ }
}
void FilterClientCallbackImpl::onFilterEvent(const DemuxFilterEvent& filterEvent) {
@@ -828,10 +857,16 @@ void FilterClientCallbackImpl::onFilterEvent(const DemuxFilterEvent& filterEvent
void FilterClientCallbackImpl::onFilterStatus(const DemuxFilterStatus status) {
ALOGD("FilterClientCallbackImpl::onFilterStatus");
JNIEnv *env = AndroidRuntime::getJNIEnv();
- env->CallVoidMethod(
- mFilterObj,
- gFields.onFilterStatusID,
- (jint)status);
+ jobject filter(env->NewLocalRef(mFilterObj));
+ if (!env->IsSameObject(filter, nullptr)) {
+ env->CallVoidMethod(
+ filter,
+ gFields.onFilterStatusID,
+ (jint)status);
+ } else {
+ ALOGE("FilterClientCallbackImpl::onFilterStatus:"
+ "Filter object has been freed. Ignoring callback.");
+ }
}
void FilterClientCallbackImpl::setFilter(jweak filterObj, sp<FilterClient> filterClient) {
@@ -841,6 +876,15 @@ void FilterClientCallbackImpl::setFilter(jweak filterObj, sp<FilterClient> filte
mFilterClient = filterClient;
}
+FilterClientCallbackImpl::~FilterClientCallbackImpl() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ if (mFilterObj != NULL) {
+ env->DeleteWeakGlobalRef(mFilterObj);
+ mFilterObj = NULL;
+ }
+ mFilterClient = NULL;
+}
+
/////////////// FrontendClientCallbackImpl ///////////////////////
FrontendClientCallbackImpl::FrontendClientCallbackImpl(jweak tunerObj) : mObject(tunerObj) {}
@@ -848,10 +892,16 @@ FrontendClientCallbackImpl::FrontendClientCallbackImpl(jweak tunerObj) : mObject
void FrontendClientCallbackImpl::onEvent(FrontendEventType frontendEventType) {
ALOGD("FrontendClientCallbackImpl::onEvent, type=%d", frontendEventType);
JNIEnv *env = AndroidRuntime::getJNIEnv();
- env->CallVoidMethod(
- mObject,
- gFields.onFrontendEventID,
- (jint)frontendEventType);
+ jobject frontend(env->NewLocalRef(mObject));
+ if (!env->IsSameObject(frontend, nullptr)) {
+ env->CallVoidMethod(
+ frontend,
+ gFields.onFrontendEventID,
+ (jint)frontendEventType);
+ } else {
+ ALOGE("FrontendClientCallbackImpl::onEvent:"
+ "Frontend object has been freed. Ignoring callback.");
+ }
}
void FrontendClientCallbackImpl::onScanMessage(
@@ -859,11 +909,17 @@ void FrontendClientCallbackImpl::onScanMessage(
ALOGD("FrontendClientCallbackImpl::onScanMessage, type=%d", type);
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass clazz = env->FindClass("android/media/tv/tuner/Tuner");
+ jobject frontend(env->NewLocalRef(mObject));
+ if (env->IsSameObject(frontend, nullptr)) {
+ ALOGE("FrontendClientCallbackImpl::onScanMessage:"
+ "Frontend object has been freed. Ignoring callback.");
+ return;
+ }
switch(type) {
case FrontendScanMessageType::LOCKED: {
if (message.isLocked()) {
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onLocked", "()V"));
}
break;
@@ -871,14 +927,14 @@ void FrontendClientCallbackImpl::onScanMessage(
case FrontendScanMessageType::END: {
if (message.isEnd()) {
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onScanStopped", "()V"));
}
break;
}
case FrontendScanMessageType::PROGRESS_PERCENT: {
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onProgress", "(I)V"),
(jint) message.progressPercent());
break;
@@ -889,7 +945,7 @@ void FrontendClientCallbackImpl::onScanMessage(
env->SetIntArrayRegion(freqs, 0, v.size(), reinterpret_cast<jint*>(&v[0]));
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onFrequenciesReport", "([I)V"),
freqs);
break;
@@ -900,21 +956,21 @@ void FrontendClientCallbackImpl::onScanMessage(
env->SetIntArrayRegion(symbolRates, 0, v.size(), reinterpret_cast<jint*>(&v[0]));
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onSymbolRates", "([I)V"),
symbolRates);
break;
}
case FrontendScanMessageType::HIERARCHY: {
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onHierarchy", "(I)V"),
(jint) message.hierarchy());
break;
}
case FrontendScanMessageType::ANALOG_TYPE: {
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onSignalType", "(I)V"),
(jint) message.analogType());
break;
@@ -926,7 +982,7 @@ void FrontendClientCallbackImpl::onScanMessage(
env->SetIntArrayRegion(plpIds, 0, jintV.size(), &jintV[0]);
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onPlpIds", "([I)V"),
plpIds);
break;
@@ -938,7 +994,7 @@ void FrontendClientCallbackImpl::onScanMessage(
env->SetIntArrayRegion(groupIds, 0, jintV.size(), &jintV[0]);
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onGroupIds", "([I)V"),
groupIds);
break;
@@ -950,7 +1006,7 @@ void FrontendClientCallbackImpl::onScanMessage(
env->SetIntArrayRegion(streamIds, 0, jintV.size(), &jintV[0]);
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onInputStreamIds", "([I)V"),
streamIds);
break;
@@ -961,21 +1017,21 @@ void FrontendClientCallbackImpl::onScanMessage(
if (std.getDiscriminator() == FrontendScanMessage::Standard::hidl_discriminator::sStd) {
standard = (jint) std.sStd();
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onDvbsStandard", "(I)V"),
standard);
} else if (std.getDiscriminator() ==
FrontendScanMessage::Standard::hidl_discriminator::tStd) {
standard = (jint) std.tStd();
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onDvbtStandard", "(I)V"),
standard);
} else if (std.getDiscriminator() ==
FrontendScanMessage::Standard::hidl_discriminator::sifStd) {
standard = (jint) std.sifStd();
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onAnalogSifStandard", "(I)V"),
standard);
}
@@ -996,7 +1052,7 @@ void FrontendClientCallbackImpl::onScanMessage(
env->SetObjectArrayElement(array, i, obj);
}
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onAtsc3PlpInfos",
"([Landroid/media/tv/tuner/frontend/Atsc3PlpInfo;)V"),
array);
@@ -1010,6 +1066,12 @@ void FrontendClientCallbackImpl::onScanMessageExt1_1(FrontendScanMessageTypeExt1
ALOGD("FrontendClientCallbackImpl::onScanMessageExt1_1, type=%d", type);
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass clazz = env->FindClass("android/media/tv/tuner/Tuner");
+ jobject frontend(env->NewLocalRef(mObject));
+ if (env->IsSameObject(frontend, nullptr)) {
+ ALOGE("FrontendClientCallbackImpl::onScanMessageExt1_1:"
+ "Frontend object has been freed. Ignoring callback.");
+ return;
+ }
switch(type) {
case FrontendScanMessageTypeExt1_1::MODULATION: {
jint modulation = -1;
@@ -1056,7 +1118,7 @@ void FrontendClientCallbackImpl::onScanMessageExt1_1(FrontendScanMessageTypeExt1
}
if (modulation > 0) {
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onModulationReported", "(I)V"),
modulation);
}
@@ -1065,7 +1127,7 @@ void FrontendClientCallbackImpl::onScanMessageExt1_1(FrontendScanMessageTypeExt1
case FrontendScanMessageTypeExt1_1::HIGH_PRIORITY: {
bool isHighPriority = message.isHighPriority();
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onPriorityReported", "(B)V"),
isHighPriority);
break;
@@ -1073,7 +1135,7 @@ void FrontendClientCallbackImpl::onScanMessageExt1_1(FrontendScanMessageTypeExt1
case FrontendScanMessageTypeExt1_1::DVBC_ANNEX: {
jint dvbcAnnex = (jint) message.annex();
env->CallVoidMethod(
- mObject,
+ frontend,
env->GetMethodID(clazz, "onDvbcAnnexReported", "(I)V"),
dvbcAnnex);
break;
@@ -1083,6 +1145,14 @@ void FrontendClientCallbackImpl::onScanMessageExt1_1(FrontendScanMessageTypeExt1
}
}
+FrontendClientCallbackImpl::~FrontendClientCallbackImpl() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ if (mObject != NULL) {
+ env->DeleteWeakGlobalRef(mObject);
+ mObject = NULL;
+ }
+}
+
/////////////// Tuner ///////////////////////
sp<TunerClient> JTuner::mTunerClient;
@@ -1158,15 +1228,22 @@ jobject JTuner::openFrontendByHandle(int feHandle) {
if (mDemuxClient != NULL) {
mDemuxClient->setFrontendDataSource(mFeClient);
}
- sp<FrontendClientCallbackImpl> feClientCb = new FrontendClientCallbackImpl(mObject);
- mFeClient->setCallback(feClientCb);
JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jobject tuner(env->NewLocalRef(mObject));
+ if (env->IsSameObject(tuner, nullptr)) {
+ ALOGE("openFrontendByHandle"
+ "Tuner object has been freed. Failed to open frontend.");
+ return NULL;
+ }
+
+ sp<FrontendClientCallbackImpl> feClientCb = new FrontendClientCallbackImpl(mObject);
+ mFeClient->setCallback(feClientCb);
// TODO: add more fields to frontend
return env->NewObject(
env->FindClass("android/media/tv/tuner/Tuner$Frontend"),
gFields.frontendInitID,
- mObject,
+ tuner,
(jint) mFeId);
}
@@ -1714,16 +1791,14 @@ jobject JTuner::openDvr(DvrType type, jlong bufferSize) {
dvrObj =
env->NewObject(
env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"),
- gFields.dvrRecorderInitID,
- mObject);
+ gFields.dvrRecorderInitID);
dvrClient->incStrong(dvrObj);
env->SetLongField(dvrObj, gFields.dvrRecorderContext, (jlong)dvrClient.get());
} else {
dvrObj =
env->NewObject(
env->FindClass("android/media/tv/tuner/dvr/DvrPlayback"),
- gFields.dvrPlaybackInitID,
- mObject);
+ gFields.dvrPlaybackInitID);
dvrClient->incStrong(dvrObj);
env->SetLongField(dvrObj, gFields.dvrPlaybackContext, (jlong)dvrClient.get());
}
@@ -2126,6 +2201,10 @@ jobject JTuner::getFrontendStatus(jintArray types) {
intBandwidth = static_cast<jint>(bandwidth.dvbt());
break;
}
+ case FrontendBandwidth::hidl_discriminator::dvbc: {
+ intBandwidth = static_cast<jint>(bandwidth.dvbc());
+ break;
+ }
case FrontendBandwidth::hidl_discriminator::isdbt: {
intBandwidth = static_cast<jint>(bandwidth.isdbt());
break;
@@ -2646,12 +2725,10 @@ static FrontendSettings getDvbsFrontendSettings(JNIEnv *env, const jobject& sett
FrontendDvbsVcmMode vcmMode =
static_cast<FrontendDvbsVcmMode>(
env->GetIntField(settings, env->GetFieldID(clazz, "mVcmMode", "I")));
- FrontendDvbsCodeRate coderate = getDvbsCodeRate(env, settings);
FrontendDvbsSettings frontendDvbsSettings {
.frequency = freq,
.modulation = modulation,
- .coderate = coderate,
.symbolRate = symbolRate,
.rolloff = rolloff,
.pilot = pilot,
@@ -2659,6 +2736,13 @@ static FrontendSettings getDvbsFrontendSettings(JNIEnv *env, const jobject& sett
.standard = standard,
.vcmMode = vcmMode,
};
+
+ jobject jcodeRate = env->GetObjectField(settings, env->GetFieldID(clazz, "mCodeRate",
+ "Landroid/media/tv/tuner/frontend/DvbsCodeRate;"));
+ if (jcodeRate != NULL) {
+ frontendDvbsSettings.coderate = getDvbsCodeRate(env, settings);
+ }
+
frontendSettings.dvbs(frontendDvbsSettings);
return frontendSettings;
}
@@ -2670,7 +2754,7 @@ static void getDvbsFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings,
static_cast<FrontendDvbsScanType>(
env->GetIntField(settings, env->GetFieldID(clazz, "mScanType", "I")));
bool isDiseqcRxMessage = static_cast<bool>(env->GetBooleanField(
- settings, env->GetFieldID(clazz, "mIsDiseqcRxMessage", "B")));
+ settings, env->GetFieldID(clazz, "mIsDiseqcRxMessage", "Z")));
FrontendDvbsSettingsExt1_1 dvbsExt1_1 {
.scanType = scanType,
@@ -2910,6 +2994,10 @@ static void getDtmbFrontendSettings(JNIEnv *env, const jobject& settings,
static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject settings) {
ALOGD("getFrontendSettings %d", type);
+ if (type == static_cast<int>(::android::hardware::tv::tuner::V1_1::FrontendType::DTMB)) {
+ return FrontendSettings();
+ }
+
FrontendType feType = static_cast<FrontendType>(type);
switch(feType) {
case FrontendType::ANALOG:
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 0e30b18eb2d4..fafef4221541 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -118,6 +118,7 @@ struct MediaEvent : public RefBase {
};
struct FilterClientCallbackImpl : public FilterClientCallback {
+ ~FilterClientCallbackImpl();
virtual void onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
const DemuxFilterEventExt& filterEventExt);
virtual void onFilterEvent(const DemuxFilterEvent& filterEvent);
@@ -155,7 +156,7 @@ private:
struct FrontendClientCallbackImpl : public FrontendClientCallback {
FrontendClientCallbackImpl(jweak tunerObj);
-
+ ~FrontendClientCallbackImpl();
virtual void onEvent(FrontendEventType frontendEventType);
virtual void onScanMessage(
FrontendScanMessageType type, const FrontendScanMessage& message);
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 4efdcaccf7a1..ffed4747d3ea 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -32,6 +32,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
+#include "core_jni_helpers.h"
#include <jni.h>
#include <media/stagefright/NuMediaExtractor.h>
#include <nativehelper/JNIHelp.h>
@@ -48,6 +49,7 @@ using namespace android;
// ----------------------------------------------------------------------------
+// MtpDatabase methods
static jmethodID method_beginSendObject;
static jmethodID method_endSendObject;
static jmethodID method_rescanFile;
@@ -75,6 +77,7 @@ static jmethodID method_endCopyObject;
static jmethodID method_getObjectReferences;
static jmethodID method_setObjectReferences;
+// MtpDatabase fields.
static jfieldID field_context;
// MtpPropertyList methods
@@ -86,6 +89,59 @@ static jmethodID method_getDataTypes;
static jmethodID method_getLongValues;
static jmethodID method_getStringValues;
+// Initializer for the jfieldIDs and jmethodIDs above. This method must be invoked
+// before using these static fields and methods for JNI accesses.
+static void initializeJavaIDs(JNIEnv* env) {
+ static std::once_flag sJniInitialized;
+
+#define GET_METHOD_ID(name, jclass, signature) \
+ method_##name = GetMethodIDOrDie(env, jclass, #name, signature);
+
+ std::call_once(sJniInitialized, [](JNIEnv* env) {
+ const jclass mdb_class = FindClassOrDie(env, "android/mtp/MtpDatabase");
+ GET_METHOD_ID(beginSendObject, mdb_class, "(Ljava/lang/String;III)I");
+ GET_METHOD_ID(endSendObject, mdb_class, "(IZ)V");
+ GET_METHOD_ID(rescanFile, mdb_class, "(Ljava/lang/String;II)V");
+ GET_METHOD_ID(getObjectList, mdb_class, "(III)[I");
+ GET_METHOD_ID(getNumObjects, mdb_class, "(III)I");
+ GET_METHOD_ID(getSupportedPlaybackFormats, mdb_class, "()[I");
+ GET_METHOD_ID(getSupportedCaptureFormats, mdb_class, "()[I");
+ GET_METHOD_ID(getSupportedObjectProperties, mdb_class, "(I)[I");
+ GET_METHOD_ID(getSupportedDeviceProperties, mdb_class, "()[I");
+ GET_METHOD_ID(setObjectProperty, mdb_class, "(IIJLjava/lang/String;)I");
+ GET_METHOD_ID(getDeviceProperty, mdb_class, "(I[J[C)I");
+ GET_METHOD_ID(setDeviceProperty, mdb_class, "(IJLjava/lang/String;)I");
+ GET_METHOD_ID(getObjectPropertyList, mdb_class, "(IIIII)Landroid/mtp/MtpPropertyList;");
+ GET_METHOD_ID(getObjectInfo, mdb_class, "(I[I[C[J)Z");
+ GET_METHOD_ID(getObjectFilePath, mdb_class, "(I[C[J)I");
+ GET_METHOD_ID(openFilePath, mdb_class, "(Ljava/lang/String;Z)I");
+ GET_METHOD_ID(getThumbnailInfo, mdb_class, "(I[J)Z");
+ GET_METHOD_ID(getThumbnailData, mdb_class, "(I)[B");
+ GET_METHOD_ID(beginDeleteObject, mdb_class, "(I)I");
+ GET_METHOD_ID(endDeleteObject, mdb_class, "(IZ)V");
+ GET_METHOD_ID(beginMoveObject, mdb_class, "(III)I");
+ GET_METHOD_ID(endMoveObject, mdb_class, "(IIIIIZ)V");
+ GET_METHOD_ID(beginCopyObject, mdb_class, "(III)I");
+ GET_METHOD_ID(endCopyObject, mdb_class, "(IZ)V");
+ GET_METHOD_ID(getObjectReferences, mdb_class, "(I)[I");
+ GET_METHOD_ID(setObjectReferences, mdb_class, "(I[I)I");
+ field_context = GetFieldIDOrDie(env, mdb_class, "mNativeContext", "J");
+
+ const jclass mpl_class = FindClassOrDie(env, "android/mtp/MtpPropertyList");
+ GET_METHOD_ID(getCode, mpl_class, "()I");
+ GET_METHOD_ID(getCount, mpl_class, "()I");
+ GET_METHOD_ID(getObjectHandles, mpl_class, "()[I");
+ GET_METHOD_ID(getPropertyCodes, mpl_class, "()[I");
+ GET_METHOD_ID(getDataTypes, mpl_class, "()[I");
+ GET_METHOD_ID(getLongValues, mpl_class, "()[J");
+ GET_METHOD_ID(getStringValues, mpl_class, "()[Ljava/lang/String;");
+
+ return 0;
+ }, env);
+
+#undef GET_METHOD_ID
+}
+
IMtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) {
return (IMtpDatabase *)env->GetLongField(database, field_context);
@@ -1280,6 +1336,7 @@ MtpProperty* MtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
static void
android_mtp_MtpDatabase_setup(JNIEnv *env, jobject thiz)
{
+ initializeJavaIDs(env);
MtpDatabase* database = new MtpDatabase(env, thiz);
env->SetLongField(thiz, field_context, (jlong)database);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
@@ -1314,69 +1371,9 @@ static const JNINativeMethod gMtpPropertyGroupMethods[] = {
{"format_date_time", "(J)Ljava/lang/String;",
(void *)android_mtp_MtpPropertyGroup_format_date_time},
};
-
-#define GET_METHOD_ID(name, jclass, signature) \
- method_##name = env->GetMethodID(jclass, #name, signature); \
- if (method_##name == NULL) { \
- ALOGE("Can't find " #name); \
- return -1; \
- } \
-
+ \
int register_android_mtp_MtpDatabase(JNIEnv *env)
{
- jclass clazz;
-
- clazz = env->FindClass("android/mtp/MtpDatabase");
- if (clazz == NULL) {
- ALOGE("Can't find android/mtp/MtpDatabase");
- return -1;
- }
- GET_METHOD_ID(beginSendObject, clazz, "(Ljava/lang/String;III)I");
- GET_METHOD_ID(endSendObject, clazz, "(IZ)V");
- GET_METHOD_ID(rescanFile, clazz, "(Ljava/lang/String;II)V");
- GET_METHOD_ID(getObjectList, clazz, "(III)[I");
- GET_METHOD_ID(getNumObjects, clazz, "(III)I");
- GET_METHOD_ID(getSupportedPlaybackFormats, clazz, "()[I");
- GET_METHOD_ID(getSupportedCaptureFormats, clazz, "()[I");
- GET_METHOD_ID(getSupportedObjectProperties, clazz, "(I)[I");
- GET_METHOD_ID(getSupportedDeviceProperties, clazz, "()[I");
- GET_METHOD_ID(setObjectProperty, clazz, "(IIJLjava/lang/String;)I");
- GET_METHOD_ID(getDeviceProperty, clazz, "(I[J[C)I");
- GET_METHOD_ID(setDeviceProperty, clazz, "(IJLjava/lang/String;)I");
- GET_METHOD_ID(getObjectPropertyList, clazz, "(IIIII)Landroid/mtp/MtpPropertyList;");
- GET_METHOD_ID(getObjectInfo, clazz, "(I[I[C[J)Z");
- GET_METHOD_ID(getObjectFilePath, clazz, "(I[C[J)I");
- GET_METHOD_ID(openFilePath, clazz, "(Ljava/lang/String;Z)I");
- GET_METHOD_ID(getThumbnailInfo, clazz, "(I[J)Z");
- GET_METHOD_ID(getThumbnailData, clazz, "(I)[B");
- GET_METHOD_ID(beginDeleteObject, clazz, "(I)I");
- GET_METHOD_ID(endDeleteObject, clazz, "(IZ)V");
- GET_METHOD_ID(beginMoveObject, clazz, "(III)I");
- GET_METHOD_ID(endMoveObject, clazz, "(IIIIIZ)V");
- GET_METHOD_ID(beginCopyObject, clazz, "(III)I");
- GET_METHOD_ID(endCopyObject, clazz, "(IZ)V");
- GET_METHOD_ID(getObjectReferences, clazz, "(I)[I");
- GET_METHOD_ID(setObjectReferences, clazz, "(I[I)I");
-
- field_context = env->GetFieldID(clazz, "mNativeContext", "J");
- if (field_context == NULL) {
- ALOGE("Can't find MtpDatabase.mNativeContext");
- return -1;
- }
-
- clazz = env->FindClass("android/mtp/MtpPropertyList");
- if (clazz == NULL) {
- ALOGE("Can't find android/mtp/MtpPropertyList");
- return -1;
- }
- GET_METHOD_ID(getCode, clazz, "()I");
- GET_METHOD_ID(getCount, clazz, "()I");
- GET_METHOD_ID(getObjectHandles, clazz, "()[I");
- GET_METHOD_ID(getPropertyCodes, clazz, "()[I");
- GET_METHOD_ID(getDataTypes, clazz, "()[I");
- GET_METHOD_ID(getLongValues, clazz, "()[J");
- GET_METHOD_ID(getStringValues, clazz, "()[Ljava/lang/String;");
-
if (AndroidRuntime::registerNativeMethods(env,
"android/mtp/MtpDatabase", gMtpDatabaseMethods, NELEM(gMtpDatabaseMethods)))
return -1;
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 060eaf9ccad4..3d2b00fec26c 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -34,6 +34,7 @@
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
+#include "core_jni_helpers.h"
#include "nativehelper/ScopedLocalRef.h"
#include "private/android_filesystem_config.h"
@@ -107,6 +108,95 @@ static jfieldID field_event_parameter1;
static jfieldID field_event_parameter2;
static jfieldID field_event_parameter3;
+// Initializer for the jclasses, jfieldIDs and jmethodIDs declared above. This method must be
+// invoked before using these static fields for JNI accesses.
+static void initializeJavaIDs(JNIEnv* env) {
+ static std::once_flag sJniInitialized;
+
+ std::call_once(sJniInitialized, [](JNIEnv* env) {
+ clazz_deviceInfo =
+ (jclass)env->NewGlobalRef(FindClassOrDie(env, "android/mtp/MtpDeviceInfo"));
+ constructor_deviceInfo = GetMethodIDOrDie(env, clazz_deviceInfo, "<init>", "()V");
+ field_deviceInfo_manufacturer =
+ GetFieldIDOrDie(env, clazz_deviceInfo, "mManufacturer", "Ljava/lang/String;");
+ field_deviceInfo_model =
+ GetFieldIDOrDie(env, clazz_deviceInfo, "mModel", "Ljava/lang/String;");
+ field_deviceInfo_version =
+ GetFieldIDOrDie(env, clazz_deviceInfo, "mVersion", "Ljava/lang/String;");
+ field_deviceInfo_serialNumber =
+ GetFieldIDOrDie(env, clazz_deviceInfo, "mSerialNumber", "Ljava/lang/String;");
+ field_deviceInfo_operationsSupported =
+ GetFieldIDOrDie(env, clazz_deviceInfo, "mOperationsSupported", "[I");
+ field_deviceInfo_eventsSupported =
+ GetFieldIDOrDie(env, clazz_deviceInfo, "mEventsSupported", "[I");
+
+ clazz_storageInfo =
+ (jclass)env->NewGlobalRef(FindClassOrDie(env, "android/mtp/MtpStorageInfo"));
+ constructor_storageInfo = GetMethodIDOrDie(env, clazz_storageInfo, "<init>", "()V");
+ field_storageInfo_storageId = GetFieldIDOrDie(env, clazz_storageInfo, "mStorageId", "I");
+ field_storageInfo_maxCapacity =
+ GetFieldIDOrDie(env, clazz_storageInfo, "mMaxCapacity", "J");
+ field_storageInfo_freeSpace =
+ GetFieldIDOrDie(env, clazz_storageInfo, "mFreeSpace", "J");
+ field_storageInfo_description =
+ GetFieldIDOrDie(env, clazz_storageInfo, "mDescription", "Ljava/lang/String;");
+ field_storageInfo_volumeIdentifier =
+ GetFieldIDOrDie(env, clazz_storageInfo, "mVolumeIdentifier", "Ljava/lang/String;");
+
+ clazz_objectInfo =
+ (jclass)env->NewGlobalRef(FindClassOrDie(env, "android/mtp/MtpObjectInfo"));
+ constructor_objectInfo = GetMethodIDOrDie(env, clazz_objectInfo, "<init>", "()V");
+ field_objectInfo_handle = GetFieldIDOrDie(env, clazz_objectInfo, "mHandle", "I");
+ field_objectInfo_storageId = GetFieldIDOrDie(env, clazz_objectInfo, "mStorageId", "I");
+ field_objectInfo_format = GetFieldIDOrDie(env, clazz_objectInfo, "mFormat", "I");
+ field_objectInfo_protectionStatus =
+ GetFieldIDOrDie(env, clazz_objectInfo, "mProtectionStatus", "I");
+ field_objectInfo_compressedSize =
+ GetFieldIDOrDie(env, clazz_objectInfo, "mCompressedSize", "I");
+ field_objectInfo_thumbFormat = GetFieldIDOrDie(env, clazz_objectInfo, "mThumbFormat", "I");
+ field_objectInfo_thumbCompressedSize =
+ GetFieldIDOrDie(env, clazz_objectInfo, "mThumbCompressedSize", "I");
+ field_objectInfo_thumbPixWidth =
+ GetFieldIDOrDie(env, clazz_objectInfo, "mThumbPixWidth", "I");
+ field_objectInfo_thumbPixHeight =
+ GetFieldIDOrDie(env, clazz_objectInfo, "mThumbPixHeight", "I");
+ field_objectInfo_imagePixWidth =
+ GetFieldIDOrDie(env, clazz_objectInfo, "mImagePixWidth", "I");
+ field_objectInfo_imagePixHeight =
+ GetFieldIDOrDie(env, clazz_objectInfo, "mImagePixHeight", "I");
+ field_objectInfo_imagePixDepth =
+ GetFieldIDOrDie(env, clazz_objectInfo, "mImagePixDepth", "I");
+ field_objectInfo_parent = GetFieldIDOrDie(env, clazz_objectInfo, "mParent", "I");
+ field_objectInfo_associationType =
+ GetFieldIDOrDie(env, clazz_objectInfo, "mAssociationType", "I");
+ field_objectInfo_associationDesc =
+ GetFieldIDOrDie(env, clazz_objectInfo, "mAssociationDesc", "I");
+ field_objectInfo_sequenceNumber =
+ GetFieldIDOrDie(env, clazz_objectInfo, "mSequenceNumber", "I");
+ field_objectInfo_name =
+ GetFieldIDOrDie(env, clazz_objectInfo, "mName", "Ljava/lang/String;");
+ field_objectInfo_dateCreated = GetFieldIDOrDie(env, clazz_objectInfo, "mDateCreated", "J");
+ field_objectInfo_dateModified =
+ GetFieldIDOrDie(env, clazz_objectInfo, "mDateModified", "J");
+ field_objectInfo_keywords =
+ GetFieldIDOrDie(env, clazz_objectInfo, "mKeywords", "Ljava/lang/String;");
+
+ clazz_event = (jclass)env->NewGlobalRef(FindClassOrDie(env, "android/mtp/MtpEvent"));
+ constructor_event = GetMethodIDOrDie(env, clazz_event, "<init>", "()V");
+ field_event_eventCode = GetFieldIDOrDie(env, clazz_event, "mEventCode", "I");
+ field_event_parameter1 = GetFieldIDOrDie(env, clazz_event, "mParameter1", "I");
+ field_event_parameter2 = GetFieldIDOrDie(env, clazz_event, "mParameter2", "I");
+ field_event_parameter3 = GetFieldIDOrDie(env, clazz_event, "mParameter3", "I");
+
+ const jclass clazz = FindClassOrDie(env, "android/mtp/MtpDevice");
+ field_context = GetFieldIDOrDie(env, clazz, "mNativeContext", "J");
+
+ clazz_io_exception = (jclass)env->NewGlobalRef(FindClassOrDie(env, "java/io/IOException"));
+ clazz_operation_canceled_exception =
+ (jclass)env->NewGlobalRef(FindClassOrDie(env, "android/os/OperationCanceledException"));
+ }, env);
+}
+
class JavaArrayWriter {
public:
JavaArrayWriter(JNIEnv* env, jbyteArray array) :
@@ -132,6 +222,11 @@ private:
MtpDevice* get_device_from_object(JNIEnv* env, jobject javaDevice)
{
+ // get_device_from_object() is called by the majority of JNI methods in this file. Call
+ // `initializeJavaIDs()` here to ensure JNI methodID's, fieldIDs and classes are initialized
+ // before use.
+ initializeJavaIDs(env);
+
return (MtpDevice*)env->GetLongField(javaDevice, field_context);
}
@@ -200,6 +295,8 @@ android_mtp_MtpDevice_open(JNIEnv *env, jobject thiz, jstring deviceName, jint f
MtpDevice* device = MtpDevice::open(deviceNameStr, fd);
env->ReleaseStringUTFChars(deviceName, deviceNameStr);
+ // The jfieldID `field_context` needs to be initialized before use below.
+ initializeJavaIDs(env);
if (device)
env->SetLongField(thiz, field_context, (jlong)device);
return (jboolean)(device != NULL);
@@ -781,256 +878,7 @@ static const JNINativeMethod gMethods[] = {
int register_android_mtp_MtpDevice(JNIEnv *env)
{
- jclass clazz;
-
ALOGD("register_android_mtp_MtpDevice\n");
-
- clazz = env->FindClass("android/mtp/MtpDeviceInfo");
- if (clazz == NULL) {
- ALOGE("Can't find android/mtp/MtpDeviceInfo");
- return -1;
- }
- constructor_deviceInfo = env->GetMethodID(clazz, "<init>", "()V");
- if (constructor_deviceInfo == NULL) {
- ALOGE("Can't find android/mtp/MtpDeviceInfo constructor");
- return -1;
- }
- field_deviceInfo_manufacturer = env->GetFieldID(clazz, "mManufacturer", "Ljava/lang/String;");
- if (field_deviceInfo_manufacturer == NULL) {
- ALOGE("Can't find MtpDeviceInfo.mManufacturer");
- return -1;
- }
- field_deviceInfo_model = env->GetFieldID(clazz, "mModel", "Ljava/lang/String;");
- if (field_deviceInfo_model == NULL) {
- ALOGE("Can't find MtpDeviceInfo.mModel");
- return -1;
- }
- field_deviceInfo_version = env->GetFieldID(clazz, "mVersion", "Ljava/lang/String;");
- if (field_deviceInfo_version == NULL) {
- ALOGE("Can't find MtpDeviceInfo.mVersion");
- return -1;
- }
- field_deviceInfo_serialNumber = env->GetFieldID(clazz, "mSerialNumber", "Ljava/lang/String;");
- if (field_deviceInfo_serialNumber == NULL) {
- ALOGE("Can't find MtpDeviceInfo.mSerialNumber");
- return -1;
- }
- field_deviceInfo_operationsSupported = env->GetFieldID(clazz, "mOperationsSupported", "[I");
- if (field_deviceInfo_operationsSupported == NULL) {
- ALOGE("Can't find MtpDeviceInfo.mOperationsSupported");
- return -1;
- }
- field_deviceInfo_eventsSupported = env->GetFieldID(clazz, "mEventsSupported", "[I");
- if (field_deviceInfo_eventsSupported == NULL) {
- ALOGE("Can't find MtpDeviceInfo.mEventsSupported");
- return -1;
- }
- clazz_deviceInfo = (jclass)env->NewGlobalRef(clazz);
-
- clazz = env->FindClass("android/mtp/MtpStorageInfo");
- if (clazz == NULL) {
- ALOGE("Can't find android/mtp/MtpStorageInfo");
- return -1;
- }
- constructor_storageInfo = env->GetMethodID(clazz, "<init>", "()V");
- if (constructor_storageInfo == NULL) {
- ALOGE("Can't find android/mtp/MtpStorageInfo constructor");
- return -1;
- }
- field_storageInfo_storageId = env->GetFieldID(clazz, "mStorageId", "I");
- if (field_storageInfo_storageId == NULL) {
- ALOGE("Can't find MtpStorageInfo.mStorageId");
- return -1;
- }
- field_storageInfo_maxCapacity = env->GetFieldID(clazz, "mMaxCapacity", "J");
- if (field_storageInfo_maxCapacity == NULL) {
- ALOGE("Can't find MtpStorageInfo.mMaxCapacity");
- return -1;
- }
- field_storageInfo_freeSpace = env->GetFieldID(clazz, "mFreeSpace", "J");
- if (field_storageInfo_freeSpace == NULL) {
- ALOGE("Can't find MtpStorageInfo.mFreeSpace");
- return -1;
- }
- field_storageInfo_description = env->GetFieldID(clazz, "mDescription", "Ljava/lang/String;");
- if (field_storageInfo_description == NULL) {
- ALOGE("Can't find MtpStorageInfo.mDescription");
- return -1;
- }
- field_storageInfo_volumeIdentifier = env->GetFieldID(clazz, "mVolumeIdentifier", "Ljava/lang/String;");
- if (field_storageInfo_volumeIdentifier == NULL) {
- ALOGE("Can't find MtpStorageInfo.mVolumeIdentifier");
- return -1;
- }
- clazz_storageInfo = (jclass)env->NewGlobalRef(clazz);
-
- clazz = env->FindClass("android/mtp/MtpObjectInfo");
- if (clazz == NULL) {
- ALOGE("Can't find android/mtp/MtpObjectInfo");
- return -1;
- }
- constructor_objectInfo = env->GetMethodID(clazz, "<init>", "()V");
- if (constructor_objectInfo == NULL) {
- ALOGE("Can't find android/mtp/MtpObjectInfo constructor");
- return -1;
- }
- field_objectInfo_handle = env->GetFieldID(clazz, "mHandle", "I");
- if (field_objectInfo_handle == NULL) {
- ALOGE("Can't find MtpObjectInfo.mHandle");
- return -1;
- }
- field_objectInfo_storageId = env->GetFieldID(clazz, "mStorageId", "I");
- if (field_objectInfo_storageId == NULL) {
- ALOGE("Can't find MtpObjectInfo.mStorageId");
- return -1;
- }
- field_objectInfo_format = env->GetFieldID(clazz, "mFormat", "I");
- if (field_objectInfo_format == NULL) {
- ALOGE("Can't find MtpObjectInfo.mFormat");
- return -1;
- }
- field_objectInfo_protectionStatus = env->GetFieldID(clazz, "mProtectionStatus", "I");
- if (field_objectInfo_protectionStatus == NULL) {
- ALOGE("Can't find MtpObjectInfo.mProtectionStatus");
- return -1;
- }
- field_objectInfo_compressedSize = env->GetFieldID(clazz, "mCompressedSize", "I");
- if (field_objectInfo_compressedSize == NULL) {
- ALOGE("Can't find MtpObjectInfo.mCompressedSize");
- return -1;
- }
- field_objectInfo_thumbFormat = env->GetFieldID(clazz, "mThumbFormat", "I");
- if (field_objectInfo_thumbFormat == NULL) {
- ALOGE("Can't find MtpObjectInfo.mThumbFormat");
- return -1;
- }
- field_objectInfo_thumbCompressedSize = env->GetFieldID(clazz, "mThumbCompressedSize", "I");
- if (field_objectInfo_thumbCompressedSize == NULL) {
- ALOGE("Can't find MtpObjectInfo.mThumbCompressedSize");
- return -1;
- }
- field_objectInfo_thumbPixWidth = env->GetFieldID(clazz, "mThumbPixWidth", "I");
- if (field_objectInfo_thumbPixWidth == NULL) {
- ALOGE("Can't find MtpObjectInfo.mThumbPixWidth");
- return -1;
- }
- field_objectInfo_thumbPixHeight = env->GetFieldID(clazz, "mThumbPixHeight", "I");
- if (field_objectInfo_thumbPixHeight == NULL) {
- ALOGE("Can't find MtpObjectInfo.mThumbPixHeight");
- return -1;
- }
- field_objectInfo_imagePixWidth = env->GetFieldID(clazz, "mImagePixWidth", "I");
- if (field_objectInfo_imagePixWidth == NULL) {
- ALOGE("Can't find MtpObjectInfo.mImagePixWidth");
- return -1;
- }
- field_objectInfo_imagePixHeight = env->GetFieldID(clazz, "mImagePixHeight", "I");
- if (field_objectInfo_imagePixHeight == NULL) {
- ALOGE("Can't find MtpObjectInfo.mImagePixHeight");
- return -1;
- }
- field_objectInfo_imagePixDepth = env->GetFieldID(clazz, "mImagePixDepth", "I");
- if (field_objectInfo_imagePixDepth == NULL) {
- ALOGE("Can't find MtpObjectInfo.mImagePixDepth");
- return -1;
- }
- field_objectInfo_parent = env->GetFieldID(clazz, "mParent", "I");
- if (field_objectInfo_parent == NULL) {
- ALOGE("Can't find MtpObjectInfo.mParent");
- return -1;
- }
- field_objectInfo_associationType = env->GetFieldID(clazz, "mAssociationType", "I");
- if (field_objectInfo_associationType == NULL) {
- ALOGE("Can't find MtpObjectInfo.mAssociationType");
- return -1;
- }
- field_objectInfo_associationDesc = env->GetFieldID(clazz, "mAssociationDesc", "I");
- if (field_objectInfo_associationDesc == NULL) {
- ALOGE("Can't find MtpObjectInfo.mAssociationDesc");
- return -1;
- }
- field_objectInfo_sequenceNumber = env->GetFieldID(clazz, "mSequenceNumber", "I");
- if (field_objectInfo_sequenceNumber == NULL) {
- ALOGE("Can't find MtpObjectInfo.mSequenceNumber");
- return -1;
- }
- field_objectInfo_name = env->GetFieldID(clazz, "mName", "Ljava/lang/String;");
- if (field_objectInfo_name == NULL) {
- ALOGE("Can't find MtpObjectInfo.mName");
- return -1;
- }
- field_objectInfo_dateCreated = env->GetFieldID(clazz, "mDateCreated", "J");
- if (field_objectInfo_dateCreated == NULL) {
- ALOGE("Can't find MtpObjectInfo.mDateCreated");
- return -1;
- }
- field_objectInfo_dateModified = env->GetFieldID(clazz, "mDateModified", "J");
- if (field_objectInfo_dateModified == NULL) {
- ALOGE("Can't find MtpObjectInfo.mDateModified");
- return -1;
- }
- field_objectInfo_keywords = env->GetFieldID(clazz, "mKeywords", "Ljava/lang/String;");
- if (field_objectInfo_keywords == NULL) {
- ALOGE("Can't find MtpObjectInfo.mKeywords");
- return -1;
- }
- clazz_objectInfo = (jclass)env->NewGlobalRef(clazz);
-
- clazz = env->FindClass("android/mtp/MtpEvent");
- if (clazz == NULL) {
- ALOGE("Can't find android/mtp/MtpEvent");
- return -1;
- }
- constructor_event = env->GetMethodID(clazz, "<init>", "()V");
- if (constructor_event == NULL) {
- ALOGE("Can't find android/mtp/MtpEvent constructor");
- return -1;
- }
- field_event_eventCode = env->GetFieldID(clazz, "mEventCode", "I");
- if (field_event_eventCode == NULL) {
- ALOGE("Can't find MtpObjectInfo.mEventCode");
- return -1;
- }
- field_event_parameter1 = env->GetFieldID(clazz, "mParameter1", "I");
- if (field_event_parameter1 == NULL) {
- ALOGE("Can't find MtpObjectInfo.mParameter1");
- return -1;
- }
- field_event_parameter2 = env->GetFieldID(clazz, "mParameter2", "I");
- if (field_event_parameter2 == NULL) {
- ALOGE("Can't find MtpObjectInfo.mParameter2");
- return -1;
- }
- field_event_parameter3 = env->GetFieldID(clazz, "mParameter3", "I");
- if (field_event_parameter3 == NULL) {
- ALOGE("Can't find MtpObjectInfo.mParameter3");
- return -1;
- }
- clazz_event = (jclass)env->NewGlobalRef(clazz);
-
- clazz = env->FindClass("android/mtp/MtpDevice");
- if (clazz == NULL) {
- ALOGE("Can't find android/mtp/MtpDevice");
- return -1;
- }
- field_context = env->GetFieldID(clazz, "mNativeContext", "J");
- if (field_context == NULL) {
- ALOGE("Can't find MtpDevice.mNativeContext");
- return -1;
- }
- clazz = env->FindClass("java/io/IOException");
- if (clazz == NULL) {
- ALOGE("Can't find java.io.IOException");
- return -1;
- }
- clazz_io_exception = (jclass)env->NewGlobalRef(clazz);
- clazz = env->FindClass("android/os/OperationCanceledException");
- if (clazz == NULL) {
- ALOGE("Can't find android.os.OperationCanceledException");
- return -1;
- }
- clazz_operation_canceled_exception = (jclass)env->NewGlobalRef(clazz);
-
return AndroidRuntime::registerNativeMethods(env,
"android/mtp/MtpDevice", gMethods, NELEM(gMethods));
}
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index 8a1ae9252ca3..b4844f79b540 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -24,6 +24,7 @@
#include <fcntl.h>
#include <utils/threads.h>
+#include "core_jni_helpers.h"
#include "jni.h"
#include <nativehelper/JNIPlatformHelp.h>
#include "android_runtime/AndroidRuntime.h"
@@ -34,6 +35,8 @@
using namespace android;
+static Mutex sMutex;
+
// MtpServer fields
static jfieldID field_MtpServer_nativeContext;
@@ -44,7 +47,25 @@ static jfieldID field_MtpStorage_description;
static jfieldID field_MtpStorage_removable;
static jfieldID field_MtpStorage_maxFileSize;
-static Mutex sMutex;
+// Initializer for the jfieldIDs above. This method must be invoked before accessing MtpServer and
+// MtpStorage fields.
+static void initializeJavaIDs(JNIEnv* env) {
+ static std::once_flag sJniInitialized;
+
+ std::call_once(sJniInitialized, [](JNIEnv *env) {
+ const jclass storage_clazz = FindClassOrDie(env, "android/mtp/MtpStorage");
+ field_MtpStorage_storageId = GetFieldIDOrDie(env, storage_clazz, "mStorageId", "I");
+ field_MtpStorage_path =
+ GetFieldIDOrDie(env, storage_clazz, "mPath", "Ljava/lang/String;");
+ field_MtpStorage_description =
+ GetFieldIDOrDie(env, storage_clazz, "mDescription", "Ljava/lang/String;");
+ field_MtpStorage_removable = GetFieldIDOrDie(env, storage_clazz, "mRemovable", "Z");
+ field_MtpStorage_maxFileSize = GetFieldIDOrDie(env, storage_clazz, "mMaxFileSize", "J");
+
+ const jclass server_clazz = FindClassOrDie(env, "android/mtp/MtpServer");
+ field_MtpServer_nativeContext = GetFieldIDOrDie(env, server_clazz, "mNativeContext", "J");
+ }, env);
+}
// ----------------------------------------------------------------------------
@@ -52,6 +73,7 @@ static Mutex sMutex;
extern IMtpDatabase* getMtpDatabase(JNIEnv *env, jobject database);
static inline MtpServer* getMtpServer(JNIEnv *env, jobject thiz) {
+ initializeJavaIDs(env);
return (MtpServer*)env->GetLongField(thiz, field_MtpServer_nativeContext);
}
@@ -60,6 +82,8 @@ android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, job
jboolean usePtp, jstring deviceInfoManufacturer, jstring deviceInfoModel,
jstring deviceInfoDeviceVersion, jstring deviceInfoSerialNumber)
{
+ initializeJavaIDs(env);
+
const char *deviceInfoManufacturerStr = env->GetStringUTFChars(deviceInfoManufacturer, NULL);
const char *deviceInfoModelStr = env->GetStringUTFChars(deviceInfoModel, NULL);
const char *deviceInfoDeviceVersionStr = env->GetStringUTFChars(deviceInfoDeviceVersion, NULL);
@@ -224,50 +248,6 @@ static const JNINativeMethod gMethods[] = {
int register_android_mtp_MtpServer(JNIEnv *env)
{
- jclass clazz;
-
- clazz = env->FindClass("android/mtp/MtpStorage");
- if (clazz == NULL) {
- ALOGE("Can't find android/mtp/MtpStorage");
- return -1;
- }
- field_MtpStorage_storageId = env->GetFieldID(clazz, "mStorageId", "I");
- if (field_MtpStorage_storageId == NULL) {
- ALOGE("Can't find MtpStorage.mStorageId");
- return -1;
- }
- field_MtpStorage_path = env->GetFieldID(clazz, "mPath", "Ljava/lang/String;");
- if (field_MtpStorage_path == NULL) {
- ALOGE("Can't find MtpStorage.mPath");
- return -1;
- }
- field_MtpStorage_description = env->GetFieldID(clazz, "mDescription", "Ljava/lang/String;");
- if (field_MtpStorage_description == NULL) {
- ALOGE("Can't find MtpStorage.mDescription");
- return -1;
- }
- field_MtpStorage_removable = env->GetFieldID(clazz, "mRemovable", "Z");
- if (field_MtpStorage_removable == NULL) {
- ALOGE("Can't find MtpStorage.mRemovable");
- return -1;
- }
- field_MtpStorage_maxFileSize = env->GetFieldID(clazz, "mMaxFileSize", "J");
- if (field_MtpStorage_maxFileSize == NULL) {
- ALOGE("Can't find MtpStorage.mMaxFileSize");
- return -1;
- }
-
- clazz = env->FindClass("android/mtp/MtpServer");
- if (clazz == NULL) {
- ALOGE("Can't find android/mtp/MtpServer");
- return -1;
- }
- field_MtpServer_nativeContext = env->GetFieldID(clazz, "mNativeContext", "J");
- if (field_MtpServer_nativeContext == NULL) {
- ALOGE("Can't find MtpServer.mNativeContext");
- return -1;
- }
-
return AndroidRuntime::registerNativeMethods(env,
"android/mtp/MtpServer", gMethods, NELEM(gMethods));
}
diff --git a/media/jni/soundpool/Android.bp b/media/jni/soundpool/Android.bp
index 7b498e027d1c..b3406cd89046 100644
--- a/media/jni/soundpool/Android.bp
+++ b/media/jni/soundpool/Android.bp
@@ -45,26 +45,30 @@ tidy_errors = [
"modernize-return-braced-init-list",
"modernize-shrink-to-fit",
"modernize-unary-static-assert",
- "modernize-use-auto", // debatable - auto can obscure type
+ // "modernize-use-auto", // found in StreamManager.h, debatable - auto can obscure type
"modernize-use-bool-literals",
"modernize-use-default-member-init",
"modernize-use-emplace",
"modernize-use-equals-default",
"modernize-use-equals-delete",
- "modernize-use-nodiscard",
+ // "modernize-use-nodiscard", // found in SteamManager.h
"modernize-use-noexcept",
"modernize-use-nullptr",
"modernize-use-override",
//"modernize-use-trailing-return-type", // not necessarily more readable
"modernize-use-transparent-functors",
"modernize-use-uncaught-exceptions",
- "modernize-use-using",
+ //"modernize-use-using", // found in SoundManager.h
"performance-*",
// Remove some pedantic stylistic requirements.
"-google-readability-casting", // C++ casts not always necessary and may be verbose
"-google-readability-todo", // do not require TODO(info)
"-google-build-using-namespace", // Reenable and fix later.
+
+ "-google-explicit-constructor", // found in StreamManager.h
+ "-misc-non-private-member-variables-in-classes", // found in SoundManager.h
+ "-performance-unnecessary-value-param", // found in StreamManager.h
]
cc_defaults {
@@ -96,8 +100,7 @@ cc_defaults {
tidy_checks: tidy_errors,
tidy_checks_as_errors: tidy_errors,
tidy_flags: [
- "-format-style='file'",
- "--header-filter='frameworks/base/media/jni/soundpool'",
+ "-format-style=file",
],
}
diff --git a/media/jni/tuner/FrontendClient.cpp b/media/jni/tuner/FrontendClient.cpp
index f400a7157051..f54e2663843c 100644
--- a/media/jni/tuner/FrontendClient.cpp
+++ b/media/jni/tuner/FrontendClient.cpp
@@ -588,14 +588,15 @@ vector<FrontendStatusExt1_1> FrontendClient::getHidlStatusExt(
break;
}
case TunerFrontendStatus::codeRates: {
- int size = s.get<TunerFrontendStatus::codeRates>().size();
- status.codeRates().resize(size);
- for (int i = 0; i < size; i++) {
- auto aidlCodeRate = s.get<TunerFrontendStatus::codeRates>()[i];
- status.codeRates()[i] =
- static_cast<hardware::tv::tuner::V1_1::FrontendInnerFec>(aidlCodeRate);
+ vector<hardware::tv::tuner::V1_1::FrontendInnerFec> codeRates;
+ for (auto aidlCodeRate : s.get<TunerFrontendStatus::codeRates>()) {
+ codeRates.push_back(
+ static_cast<hardware::tv::tuner::V1_1::FrontendInnerFec>(aidlCodeRate));
+ }
+ if (codeRates.size() > 0) {
+ status.codeRates(codeRates);
+ hidlStatus.push_back(status);
}
- hidlStatus.push_back(status);
break;
}
case TunerFrontendStatus::bandwidth: {
diff --git a/native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp b/native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp
index 1a51218616d2..fdca3fad2383 100644
--- a/native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp
+++ b/native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test_helper_app {
name: "UidImportanceHelperApp",
manifest: "HelperAppManifest.xml",
@@ -8,4 +17,3 @@ android_test_helper_app {
"general-tests",
],
}
-
diff --git a/native/android/tests/activitymanager/nativeTests/Android.bp b/native/android/tests/activitymanager/nativeTests/Android.bp
index d4b5015ad8f3..528ac12c16b7 100644
--- a/native/android/tests/activitymanager/nativeTests/Android.bp
+++ b/native/android/tests/activitymanager/nativeTests/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
cc_test {
name: "ActivityManagerNativeTestCases",
diff --git a/packages/CompanionDeviceManager/AndroidManifest.xml b/packages/CompanionDeviceManager/AndroidManifest.xml
index 91bad7b4aa91..f9795c601431 100644
--- a/packages/CompanionDeviceManager/AndroidManifest.xml
+++ b/packages/CompanionDeviceManager/AndroidManifest.xml
@@ -41,13 +41,13 @@
android:supportsRtl="true">
<service
- android:name=".DeviceDiscoveryService"
+ android:name=".CompanionDeviceDiscoveryService"
android:permission="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE"
android:exported="true">
</service>
<activity
- android:name=".DeviceChooserActivity"
+ android:name=".CompanionDeviceActivity"
android:theme="@style/ChooserActivity"
android:permission="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE"
android:exported="true">
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index c30d4bf322cf..28072ca4f113 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE
import static java.util.Objects.requireNonNull;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.companion.AssociationRequest;
@@ -31,41 +32,52 @@ import android.companion.CompanionDeviceManager;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.database.DataSetObserver;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.Html;
import android.util.Log;
+import android.util.SparseArray;
+import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
-import android.widget.AdapterView;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.android.companiondevicemanager.DeviceDiscoveryService.DeviceFilterPair;
+import com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DeviceFilterPair;
import com.android.internal.util.Preconditions;
-public class DeviceChooserActivity extends Activity {
+public class CompanionDeviceActivity extends Activity {
private static final boolean DEBUG = false;
- private static final String LOG_TAG = "DeviceChooserActivity";
+ private static final String LOG_TAG = CompanionDeviceActivity.class.getSimpleName();
+
+ static CompanionDeviceActivity sInstance;
View mLoadingIndicator = null;
ListView mDeviceListView;
private View mPairButton;
private View mCancelButton;
+ DevicesAdapter mDevicesAdapter;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (DEBUG) Log.i(LOG_TAG, "Started with intent " + getIntent());
+ Log.i(LOG_TAG, "Starting UI for " + getService().mRequest);
if (getService().mDevicesFound.isEmpty()) {
Log.e(LOG_TAG, "About to show UI, but no devices to show");
}
getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+ sInstance = this;
String deviceProfile = getRequest().getDeviceProfile();
String profilePrivacyDisclaimer = emptyIfNull(getRequest()
@@ -96,17 +108,14 @@ public class DeviceChooserActivity extends Activity {
profileName,
getCallingAppName()), 0));
mDeviceListView = findViewById(R.id.device_list);
- final DeviceDiscoveryService.DevicesAdapter adapter = getService().mDevicesAdapter;
- mDeviceListView.setAdapter(adapter);
- mDeviceListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> adapterView, View view, int pos, long l) {
- getService().mSelectedDevice =
- (DeviceFilterPair) adapterView.getItemAtPosition(pos);
- adapter.notifyDataSetChanged();
- }
+ mDevicesAdapter = new DevicesAdapter();
+ mDeviceListView.setAdapter(mDevicesAdapter);
+ mDeviceListView.setOnItemClickListener((adapterView, view, pos, l) -> {
+ getService().mSelectedDevice =
+ (DeviceFilterPair) adapterView.getItemAtPosition(pos);
+ mDevicesAdapter.notifyDataSetChanged();
});
- adapter.registerDataSetObserver(new DataSetObserver() {
+ mDevicesAdapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
onSelectionUpdate();
@@ -133,6 +142,12 @@ public class DeviceChooserActivity extends Activity {
mCancelButton.setOnClickListener(v -> cancel());
}
+ static void notifyDevicesChanged() {
+ if (sInstance != null && !sInstance.isFinishing()) {
+ sInstance.mDevicesAdapter.notifyDataSetChanged();
+ }
+ }
+
private AssociationRequest getRequest() {
return getService().mRequest;
}
@@ -156,6 +171,7 @@ public class DeviceChooserActivity extends Activity {
}
private void cancel() {
+ Log.i(LOG_TAG, "cancel()");
getService().onCancel();
setResult(RESULT_CANCELED);
finish();
@@ -170,6 +186,14 @@ public class DeviceChooserActivity extends Activity {
}
}
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (sInstance == this) {
+ sInstance = null;
+ }
+ }
+
private CharSequence getCallingAppName() {
try {
final PackageManager packageManager = getPackageManager();
@@ -217,15 +241,91 @@ public class DeviceChooserActivity extends Activity {
}
}
- private DeviceDiscoveryService getService() {
- return DeviceDiscoveryService.sInstance;
+ private CompanionDeviceDiscoveryService getService() {
+ return CompanionDeviceDiscoveryService.sInstance;
}
- protected void onDeviceConfirmed(DeviceFilterPair selectedDevice) {
+ protected void onDeviceConfirmed(DeviceFilterPair selectedDevice) {
+ Log.i(LOG_TAG, "onDeviceConfirmed(selectedDevice = " + selectedDevice + ")");
getService().onDeviceSelected(
getCallingPackage(), getDeviceMacAddress(selectedDevice.device));
setResult(RESULT_OK,
new Intent().putExtra(CompanionDeviceManager.EXTRA_DEVICE, selectedDevice.device));
finish();
}
+
+ class DevicesAdapter extends BaseAdapter {
+ private final Drawable mBluetoothIcon = icon(android.R.drawable.stat_sys_data_bluetooth);
+ private final Drawable mWifiIcon = icon(com.android.internal.R.drawable.ic_wifi_signal_3);
+
+ private SparseArray<Integer> mColors = new SparseArray();
+
+ private Drawable icon(int drawableRes) {
+ Drawable icon = getResources().getDrawable(drawableRes, null);
+ icon.setTint(Color.DKGRAY);
+ return icon;
+ }
+
+ @Override
+ public View getView(
+ int position,
+ @Nullable View convertView,
+ @NonNull ViewGroup parent) {
+ TextView view = convertView instanceof TextView
+ ? (TextView) convertView
+ : newView();
+ bind(view, getItem(position));
+ return view;
+ }
+
+ private void bind(TextView textView, DeviceFilterPair device) {
+ textView.setText(device.getDisplayName());
+ textView.setBackgroundColor(
+ device.equals(getService().mSelectedDevice)
+ ? getColor(android.R.attr.colorControlHighlight)
+ : Color.TRANSPARENT);
+ textView.setCompoundDrawablesWithIntrinsicBounds(
+ device.device instanceof android.net.wifi.ScanResult
+ ? mWifiIcon
+ : mBluetoothIcon,
+ null, null, null);
+ textView.getCompoundDrawables()[0].setTint(getColor(android.R.attr.colorForeground));
+ }
+
+ private TextView newView() {
+ final TextView textView = new TextView(CompanionDeviceActivity.this);
+ textView.setTextColor(getColor(android.R.attr.colorForeground));
+ final int padding = CompanionDeviceActivity.getPadding(getResources());
+ textView.setPadding(padding, padding, padding, padding);
+ textView.setCompoundDrawablePadding(padding);
+ return textView;
+ }
+
+ private int getColor(int colorAttr) {
+ if (mColors.contains(colorAttr)) {
+ return mColors.get(colorAttr);
+ }
+ TypedValue typedValue = new TypedValue();
+ TypedArray a = obtainStyledAttributes(typedValue.data, new int[] { colorAttr });
+ int result = a.getColor(0, 0);
+ a.recycle();
+ mColors.put(colorAttr, result);
+ return result;
+ }
+
+ @Override
+ public int getCount() {
+ return getService().mDevicesFound.size();
+ }
+
+ @Override
+ public DeviceFilterPair getItem(int position) {
+ return getService().mDevicesFound.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+ }
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index 67d4b41f164c..e620dfbafa08 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -50,9 +50,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.IBinder;
@@ -60,12 +57,6 @@ import android.os.Parcelable;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
-import android.util.SparseArray;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.TextView;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.ArrayUtils;
@@ -76,14 +67,14 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
-public class DeviceDiscoveryService extends Service {
+public class CompanionDeviceDiscoveryService extends Service {
private static final boolean DEBUG = false;
- private static final String LOG_TAG = "DeviceDiscoveryService";
+ private static final String LOG_TAG = CompanionDeviceDiscoveryService.class.getSimpleName();
private static final long SCAN_TIMEOUT = 20000;
- static DeviceDiscoveryService sInstance;
+ static CompanionDeviceDiscoveryService sInstance;
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
@@ -102,12 +93,12 @@ public class DeviceDiscoveryService extends Service {
AssociationRequest mRequest;
List<DeviceFilterPair> mDevicesFound;
DeviceFilterPair mSelectedDevice;
- DevicesAdapter mDevicesAdapter;
IFindDeviceCallback mFindCallback;
AndroidFuture<Association> mServiceCallback;
boolean mIsScanning = false;
- @Nullable DeviceChooserActivity mActivity = null;
+ @Nullable
+ CompanionDeviceActivity mActivity = null;
private final ICompanionDeviceDiscoveryService mBinder =
new ICompanionDeviceDiscoveryService.Stub() {
@@ -125,7 +116,8 @@ public class DeviceDiscoveryService extends Service {
mFindCallback = findCallback;
mServiceCallback = serviceCallback;
Handler.getMain().sendMessage(obtainMessage(
- DeviceDiscoveryService::startDiscovery, DeviceDiscoveryService.this, request));
+ CompanionDeviceDiscoveryService::startDiscovery,
+ CompanionDeviceDiscoveryService.this, request));
}
};
@@ -151,7 +143,6 @@ public class DeviceDiscoveryService extends Service {
mWifiManager = getSystemService(WifiManager.class);
mDevicesFound = new ArrayList<>();
- mDevicesAdapter = new DevicesAdapter();
sInstance = this;
}
@@ -165,7 +156,8 @@ public class DeviceDiscoveryService extends Service {
mWifiFilters = CollectionUtils.filter(mFilters, WifiDeviceFilter.class);
mBluetoothFilters = CollectionUtils.filter(mFilters, BluetoothDeviceFilter.class);
mBLEFilters = CollectionUtils.filter(mFilters, BluetoothLeDeviceFilter.class);
- mBLEScanFilters = CollectionUtils.map(mBLEFilters, BluetoothLeDeviceFilter::getScanFilter);
+ mBLEScanFilters
+ = CollectionUtils.map(mBLEFilters, BluetoothLeDeviceFilter::getScanFilter);
reset();
} else if (DEBUG) Log.i(LOG_TAG, "startDiscovery: duplicate request: " + request);
@@ -223,7 +215,7 @@ public class DeviceDiscoveryService extends Service {
}
mIsScanning = true;
Handler.getMain().sendMessageDelayed(
- obtainMessage(DeviceDiscoveryService::stopScan, this),
+ obtainMessage(CompanionDeviceDiscoveryService::stopScan, this),
SCAN_TIMEOUT);
}
@@ -237,7 +229,7 @@ public class DeviceDiscoveryService extends Service {
stopScan();
mDevicesFound.clear();
mSelectedDevice = null;
- mDevicesAdapter.notifyDataSetChanged();
+ CompanionDeviceActivity.notifyDevicesChanged();
}
@Override
@@ -252,7 +244,7 @@ public class DeviceDiscoveryService extends Service {
if (!mIsScanning) return;
mIsScanning = false;
- DeviceChooserActivity activity = mActivity;
+ CompanionDeviceActivity activity = mActivity;
if (activity != null) {
if (activity.mDeviceListView != null) {
activity.mDeviceListView.removeFooterView(activity.mLoadingIndicator);
@@ -276,7 +268,7 @@ public class DeviceDiscoveryService extends Service {
if (device == null) return;
Handler.getMain().sendMessage(obtainMessage(
- DeviceDiscoveryService::onDeviceFoundMainThread, this, device));
+ CompanionDeviceDiscoveryService::onDeviceFoundMainThread, this, device));
}
@MainThread
@@ -292,7 +284,7 @@ public class DeviceDiscoveryService extends Service {
onReadyToShowUI();
}
mDevicesFound.add(device);
- mDevicesAdapter.notifyDataSetChanged();
+ CompanionDeviceActivity.notifyDevicesChanged();
}
//TODO also, on timeout -> call onFailure
@@ -300,7 +292,7 @@ public class DeviceDiscoveryService extends Service {
try {
mFindCallback.onSuccess(PendingIntent.getActivity(
this, 0,
- new Intent(this, DeviceChooserActivity.class),
+ new Intent(this, CompanionDeviceActivity.class),
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT
| PendingIntent.FLAG_IMMUTABLE));
} catch (RemoteException e) {
@@ -311,13 +303,13 @@ public class DeviceDiscoveryService extends Service {
private void onDeviceLost(@Nullable DeviceFilterPair device) {
Log.i(LOG_TAG, "Lost device " + device.getDisplayName());
Handler.getMain().sendMessage(obtainMessage(
- DeviceDiscoveryService::onDeviceLostMainThread, this, device));
+ CompanionDeviceDiscoveryService::onDeviceLostMainThread, this, device));
}
@MainThread
void onDeviceLostMainThread(@Nullable DeviceFilterPair device) {
mDevicesFound.remove(device);
- mDevicesAdapter.notifyDataSetChanged();
+ CompanionDeviceActivity.notifyDevicesChanged();
}
void onDeviceSelected(String callingPackage, String deviceAddress) {
@@ -331,81 +323,6 @@ public class DeviceDiscoveryService extends Service {
mServiceCallback.cancel(true);
}
- class DevicesAdapter extends BaseAdapter {
- private Drawable BLUETOOTH_ICON = icon(android.R.drawable.stat_sys_data_bluetooth);
- private Drawable WIFI_ICON = icon(com.android.internal.R.drawable.ic_wifi_signal_3);
-
- private SparseArray<Integer> mColors = new SparseArray();
-
- private Drawable icon(int drawableRes) {
- Drawable icon = getResources().getDrawable(drawableRes, null);
- icon.setTint(Color.DKGRAY);
- return icon;
- }
-
- @Override
- public View getView(
- int position,
- @Nullable View convertView,
- @NonNull ViewGroup parent) {
- TextView view = convertView instanceof TextView
- ? (TextView) convertView
- : newView();
- bind(view, getItem(position));
- return view;
- }
-
- private void bind(TextView textView, DeviceFilterPair device) {
- textView.setText(device.getDisplayName());
- textView.setBackgroundColor(
- device.equals(mSelectedDevice)
- ? getColor(android.R.attr.colorControlHighlight)
- : Color.TRANSPARENT);
- textView.setCompoundDrawablesWithIntrinsicBounds(
- device.device instanceof android.net.wifi.ScanResult
- ? WIFI_ICON
- : BLUETOOTH_ICON,
- null, null, null);
- textView.getCompoundDrawables()[0].setTint(getColor(android.R.attr.colorForeground));
- }
-
- private TextView newView() {
- final TextView textView = new TextView(DeviceDiscoveryService.this);
- textView.setTextColor(getColor(android.R.attr.colorForeground));
- final int padding = DeviceChooserActivity.getPadding(getResources());
- textView.setPadding(padding, padding, padding, padding);
- textView.setCompoundDrawablePadding(padding);
- return textView;
- }
-
- private int getColor(int colorAttr) {
- if (mColors.contains(colorAttr)) {
- return mColors.get(colorAttr);
- }
- TypedValue typedValue = new TypedValue();
- TypedArray a = obtainStyledAttributes(typedValue.data, new int[] { colorAttr });
- int result = a.getColor(0, 0);
- a.recycle();
- mColors.put(colorAttr, result);
- return result;
- }
-
- @Override
- public int getCount() {
- return mDevicesFound.size();
- }
-
- @Override
- public DeviceFilterPair getItem(int position) {
- return mDevicesFound.get(position);
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
- }
-
/**
* A pair of device and a filter that matched this device if any.
*
diff --git a/packages/Connectivity/framework/src/android/net/CaptivePortalData.java b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
index f4b46e9f11ed..eafda4d2d694 100644
--- a/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
+++ b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
@@ -44,7 +44,7 @@ public final class CaptivePortalData implements Parcelable {
private final boolean mCaptive;
private final String mVenueFriendlyName;
private final int mVenueInfoUrlSource;
- private final int mTermsAndConditionsSource;
+ private final int mUserPortalUrlSource;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -65,7 +65,7 @@ public final class CaptivePortalData implements Parcelable {
private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl,
boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive,
- String venueFriendlyName, int venueInfoUrlSource, int termsAndConditionsSource) {
+ String venueFriendlyName, int venueInfoUrlSource, int userPortalUrlSource) {
mRefreshTimeMillis = refreshTimeMillis;
mUserPortalUrl = userPortalUrl;
mVenueInfoUrl = venueInfoUrl;
@@ -75,7 +75,7 @@ public final class CaptivePortalData implements Parcelable {
mCaptive = captive;
mVenueFriendlyName = venueFriendlyName;
mVenueInfoUrlSource = venueInfoUrlSource;
- mTermsAndConditionsSource = termsAndConditionsSource;
+ mUserPortalUrlSource = userPortalUrlSource;
}
private CaptivePortalData(Parcel p) {
@@ -100,7 +100,7 @@ public final class CaptivePortalData implements Parcelable {
dest.writeBoolean(mCaptive);
dest.writeString(mVenueFriendlyName);
dest.writeInt(mVenueInfoUrlSource);
- dest.writeInt(mTermsAndConditionsSource);
+ dest.writeInt(mUserPortalUrlSource);
}
/**
@@ -130,7 +130,7 @@ public final class CaptivePortalData implements Parcelable {
public Builder(@Nullable CaptivePortalData data) {
if (data == null) return;
setRefreshTime(data.mRefreshTimeMillis)
- .setUserPortalUrl(data.mUserPortalUrl, data.mTermsAndConditionsSource)
+ .setUserPortalUrl(data.mUserPortalUrl, data.mUserPortalUrlSource)
.setVenueInfoUrl(data.mVenueInfoUrl, data.mVenueInfoUrlSource)
.setSessionExtendable(data.mIsSessionExtendable)
.setBytesRemaining(data.mByteLimit)
@@ -314,7 +314,7 @@ public final class CaptivePortalData implements Parcelable {
* @return The source that the user portal URL was obtained from
*/
public @CaptivePortalDataSource int getUserPortalUrlSource() {
- return mTermsAndConditionsSource;
+ return mUserPortalUrlSource;
}
/**
@@ -342,7 +342,7 @@ public final class CaptivePortalData implements Parcelable {
public int hashCode() {
return Objects.hash(mRefreshTimeMillis, mUserPortalUrl, mVenueInfoUrl,
mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive, mVenueFriendlyName,
- mVenueInfoUrlSource, mTermsAndConditionsSource);
+ mVenueInfoUrlSource, mUserPortalUrlSource);
}
@Override
@@ -358,7 +358,7 @@ public final class CaptivePortalData implements Parcelable {
&& mCaptive == other.mCaptive
&& Objects.equals(mVenueFriendlyName, other.mVenueFriendlyName)
&& mVenueInfoUrlSource == other.mVenueInfoUrlSource
- && mTermsAndConditionsSource == other.mTermsAndConditionsSource;
+ && mUserPortalUrlSource == other.mUserPortalUrlSource;
}
@Override
@@ -373,7 +373,7 @@ public final class CaptivePortalData implements Parcelable {
+ ", captive: " + mCaptive
+ ", venueFriendlyName: " + mVenueFriendlyName
+ ", venueInfoUrlSource: " + mVenueInfoUrlSource
- + ", termsAndConditionsSource: " + mTermsAndConditionsSource
+ + ", userPortalUrlSource: " + mUserPortalUrlSource
+ "}";
}
}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index 4ddae533bb80..e7ab0a1c7ac8 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -1067,58 +1067,6 @@ public class ConnectivityManager {
}
/**
- * Calls VpnManager#isAlwaysOnVpnPackageSupportedForUser.
- * @deprecated TODO: remove when callers have migrated to VpnManager.
- * @hide
- */
- @Deprecated
- public boolean isAlwaysOnVpnPackageSupportedForUser(int userId, @Nullable String vpnPackage) {
- return getVpnManager().isAlwaysOnVpnPackageSupportedForUser(userId, vpnPackage);
- }
-
- /**
- * Calls VpnManager#setAlwaysOnVpnPackageForUser.
- * @deprecated TODO: remove when callers have migrated to VpnManager.
- * @hide
- */
- @Deprecated
- public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage,
- boolean lockdownEnabled, @Nullable List<String> lockdownAllowlist) {
- return getVpnManager().setAlwaysOnVpnPackageForUser(userId, vpnPackage, lockdownEnabled,
- lockdownAllowlist);
- }
-
- /**
- * Calls VpnManager#getAlwaysOnVpnPackageForUser.
- * @deprecated TODO: remove when callers have migrated to VpnManager.
- * @hide
- */
- @Deprecated
- public String getAlwaysOnVpnPackageForUser(int userId) {
- return getVpnManager().getAlwaysOnVpnPackageForUser(userId);
- }
-
- /**
- * Calls VpnManager#isVpnLockdownEnabled.
- * @deprecated TODO: remove when callers have migrated to VpnManager.
- * @hide
- */
- @Deprecated
- public boolean isVpnLockdownEnabled(int userId) {
- return getVpnManager().isVpnLockdownEnabled(userId);
- }
-
- /**
- * Calls VpnManager#getVpnLockdownAllowlist.
- * @deprecated TODO: remove when callers have migrated to VpnManager.
- * @hide
- */
- @Deprecated
- public List<String> getVpnLockdownAllowlist(int userId) {
- return getVpnManager().getVpnLockdownAllowlist(userId);
- }
-
- /**
* Adds or removes a requirement for given UID ranges to use the VPN.
*
* If set to {@code true}, informs the system that the UIDs in the specified ranges must not
@@ -3153,16 +3101,6 @@ public class ConnectivityManager {
}
/**
- * Calls VpnManager#updateLockdownVpn.
- * @deprecated TODO: remove when callers have migrated to VpnManager.
- * @hide
- */
- @Deprecated
- public boolean updateLockdownVpn() {
- return getVpnManager().updateLockdownVpn();
- }
-
- /**
* Set sign in error notification to visible or invisible
*
* @hide
@@ -4523,8 +4461,6 @@ public class ConnectivityManager {
try {
mService.factoryReset();
mTetheringManager.stopAllTethering();
- // TODO: Migrate callers to VpnManager#factoryReset.
- getVpnManager().factoryReset();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4818,15 +4754,6 @@ public class ConnectivityManager {
return new TestNetworkManager(ITestNetworkManager.Stub.asInterface(tnBinder));
}
- /**
- * Temporary hack to shim calls from ConnectivityManager to VpnManager. We cannot store a
- * private final mVpnManager because ConnectivityManager is initialized before VpnManager.
- * @hide TODO: remove.
- */
- public VpnManager getVpnManager() {
- return mContext.getSystemService(VpnManager.class);
- }
-
/** @hide */
public ConnectivityDiagnosticsManager createDiagnosticsManager() {
return new ConnectivityDiagnosticsManager(mContext, mService);
diff --git a/packages/Connectivity/framework/src/android/net/IpPrefix.java b/packages/Connectivity/framework/src/android/net/IpPrefix.java
index bcb65fab8571..d2ee7d13b05f 100644
--- a/packages/Connectivity/framework/src/android/net/IpPrefix.java
+++ b/packages/Connectivity/framework/src/android/net/IpPrefix.java
@@ -24,6 +24,8 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pair;
+import com.android.net.module.util.NetUtils;
+
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
@@ -59,7 +61,7 @@ public final class IpPrefix implements Parcelable {
throw new IllegalArgumentException(
"IpPrefix has " + address.length + " bytes which is neither 4 nor 16");
}
- NetworkUtils.maskRawAddress(address, prefixLength);
+ NetUtils.maskRawAddress(address, prefixLength);
}
/**
@@ -190,7 +192,7 @@ public final class IpPrefix implements Parcelable {
if (addrBytes == null || addrBytes.length != this.address.length) {
return false;
}
- NetworkUtils.maskRawAddress(addrBytes, prefixLength);
+ NetUtils.maskRawAddress(addrBytes, prefixLength);
return Arrays.equals(this.address, addrBytes);
}
@@ -204,7 +206,7 @@ public final class IpPrefix implements Parcelable {
public boolean containsPrefix(@NonNull IpPrefix otherPrefix) {
if (otherPrefix.getPrefixLength() < prefixLength) return false;
final byte[] otherAddress = otherPrefix.getRawAddress();
- NetworkUtils.maskRawAddress(otherAddress, prefixLength);
+ NetUtils.maskRawAddress(otherAddress, prefixLength);
return Arrays.equals(otherAddress, address);
}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index 26d14cbfaa95..cd76f409b093 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -205,6 +205,7 @@ public final class NetworkCapabilities implements Parcelable {
NET_CAPABILITY_OEM_PRIVATE,
NET_CAPABILITY_VEHICLE_INTERNAL,
NET_CAPABILITY_NOT_VCN_MANAGED,
+ NET_CAPABILITY_ENTERPRISE,
})
public @interface NetCapability { }
@@ -415,8 +416,17 @@ public final class NetworkCapabilities implements Parcelable {
@SystemApi
public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28;
+ /**
+ * Indicates that this network is intended for enterprise use.
+ * <p>
+ * 5G URSP rules may indicate that all data should use a connection dedicated for enterprise
+ * use. If the enterprise capability is requested, all enterprise traffic will be routed over
+ * the connection with this capability.
+ */
+ public static final int NET_CAPABILITY_ENTERPRISE = 29;
+
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
- private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_VCN_MANAGED;
+ private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_ENTERPRISE;
/**
* Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -474,7 +484,8 @@ public final class NetworkCapabilities implements Parcelable {
| (1 << NET_CAPABILITY_MCX)
| (1 << NET_CAPABILITY_RCS)
| (1 << NET_CAPABILITY_VEHICLE_INTERNAL)
- | (1 << NET_CAPABILITY_XCAP);
+ | (1 << NET_CAPABILITY_XCAP)
+ | (1 << NET_CAPABILITY_ENTERPRISE);
/**
* Capabilities that force network to be restricted.
@@ -2028,8 +2039,9 @@ public final class NetworkCapabilities implements Parcelable {
case NET_CAPABILITY_PARTIAL_CONNECTIVITY: return "PARTIAL_CONNECTIVITY";
case NET_CAPABILITY_TEMPORARILY_NOT_METERED: return "TEMPORARILY_NOT_METERED";
case NET_CAPABILITY_OEM_PRIVATE: return "OEM_PRIVATE";
- case NET_CAPABILITY_VEHICLE_INTERNAL: return "NET_CAPABILITY_VEHICLE_INTERNAL";
+ case NET_CAPABILITY_VEHICLE_INTERNAL: return "VEHICLE_INTERNAL";
case NET_CAPABILITY_NOT_VCN_MANAGED: return "NOT_VCN_MANAGED";
+ case NET_CAPABILITY_ENTERPRISE: return "ENTERPRISE";
default: return Integer.toString(capability);
}
}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkUtils.java b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
index 8be4af7b1396..9ccb04a44af4 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkUtils.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
@@ -29,7 +29,6 @@ import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.SocketException;
-import java.net.UnknownHostException;
import java.util.Locale;
import java.util.TreeSet;
@@ -232,46 +231,6 @@ public class NetworkUtils {
}
/**
- * Masks a raw IP address byte array with the specified prefix length.
- */
- public static void maskRawAddress(byte[] array, int prefixLength) {
- if (prefixLength < 0 || prefixLength > array.length * 8) {
- throw new RuntimeException("IP address with " + array.length +
- " bytes has invalid prefix length " + prefixLength);
- }
-
- int offset = prefixLength / 8;
- int remainder = prefixLength % 8;
- byte mask = (byte)(0xFF << (8 - remainder));
-
- if (offset < array.length) array[offset] = (byte)(array[offset] & mask);
-
- offset++;
-
- for (; offset < array.length; offset++) {
- array[offset] = 0;
- }
- }
-
- /**
- * Get InetAddress masked with prefixLength. Will never return null.
- * @param address the IP address to mask with
- * @param prefixLength the prefixLength used to mask the IP
- */
- public static InetAddress getNetworkPart(InetAddress address, int prefixLength) {
- byte[] array = address.getAddress();
- maskRawAddress(array, prefixLength);
-
- InetAddress netPart = null;
- try {
- netPart = InetAddress.getByAddress(array);
- } catch (UnknownHostException e) {
- throw new RuntimeException("getNetworkPart error - " + e.toString());
- }
- return netPart;
- }
-
- /**
* Returns the implicit netmask of an IPv4 address, as was the custom before 1993.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
diff --git a/packages/DynamicSystemInstallationService/res/values-eu/strings.xml b/packages/DynamicSystemInstallationService/res/values-eu/strings.xml
index 6576edd386d6..b0d45e1d061a 100644
--- a/packages/DynamicSystemInstallationService/res/values-eu/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-eu/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Prest dago sistema dinamikoa. Erabiltzen hasteko, berrabiarazi gailua."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Instalatzen"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Ezin izan da instalatu"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Ezin izan da balidatu irudia. Utzi bertan behera instalazioa."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Ezin izan da baliozkotu irudia. Utzi bertan behera instalazioa."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Sistema dinamiko bat abian da. Berrabiarazi Android-en jatorrizko bertsioa erabiltzeko."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Utzi"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Baztertu"</string>
diff --git a/packages/InputDevices/OWNERS b/packages/InputDevices/OWNERS
index 0313a40f7270..f0d6db88bcc5 100644
--- a/packages/InputDevices/OWNERS
+++ b/packages/InputDevices/OWNERS
@@ -1,2 +1 @@
-michaelwr@google.com
-svv@google.com
+include /services/core/java/com/android/server/input/OWNERS
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
index 8b4db92910f5..2946db3cdcf0 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
@@ -27,9 +27,11 @@ public class LocalTransportParameters extends KeyValueSettingObserver {
private static final String SETTING = Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS;
private static final String KEY_FAKE_ENCRYPTION_FLAG = "fake_encryption_flag";
private static final String KEY_NON_INCREMENTAL_ONLY = "non_incremental_only";
+ private static final String KEY_IS_DEVICE_TRANSFER = "is_device_transfer";
private boolean mFakeEncryptionFlag;
private boolean mIsNonIncrementalOnly;
+ private boolean mIsDeviceTransfer;
public LocalTransportParameters(Handler handler, ContentResolver resolver) {
super(handler, resolver, Settings.Secure.getUriFor(SETTING));
@@ -43,6 +45,10 @@ public class LocalTransportParameters extends KeyValueSettingObserver {
return mIsNonIncrementalOnly;
}
+ boolean isDeviceTransfer() {
+ return mIsDeviceTransfer;
+ }
+
public String getSettingValue(ContentResolver resolver) {
return Settings.Secure.getString(resolver, SETTING);
}
@@ -50,5 +56,6 @@ public class LocalTransportParameters extends KeyValueSettingObserver {
public void update(KeyValueListParser parser) {
mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false);
mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, false);
+ mIsDeviceTransfer = parser.getBoolean(KEY_IS_DEVICE_TRANSFER, false);
}
}
diff --git a/packages/SettingsLib/BannerMessagePreference/Android.bp b/packages/SettingsLib/BannerMessagePreference/Android.bp
index 095975afa13a..82e837bcd3ac 100644
--- a/packages/SettingsLib/BannerMessagePreference/Android.bp
+++ b/packages/SettingsLib/BannerMessagePreference/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_library {
name: "SettingsLibBannerMessagePreference",
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
index c23ff05f34ab..ed49bf4d5385 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_library {
name: "SettingsLibCollapsingToolbarBaseActivity",
diff --git a/packages/SettingsLib/EmergencyNumber/Android.bp b/packages/SettingsLib/EmergencyNumber/Android.bp
index 3c41f7834d6c..25b4905c438f 100644
--- a/packages/SettingsLib/EmergencyNumber/Android.bp
+++ b/packages/SettingsLib/EmergencyNumber/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_library {
name: "SettingsLibEmergencyNumber",
diff --git a/packages/SettingsLib/FooterPreference/Android.bp b/packages/SettingsLib/FooterPreference/Android.bp
index 1af967fef717..11f39e7bb210 100644
--- a/packages/SettingsLib/FooterPreference/Android.bp
+++ b/packages/SettingsLib/FooterPreference/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_library {
name: "SettingsLibFooterPreference",
diff --git a/packages/SettingsLib/MainSwitchPreference/Android.bp b/packages/SettingsLib/MainSwitchPreference/Android.bp
index 1dc18f5cc4d2..1feec21e24e4 100644
--- a/packages/SettingsLib/MainSwitchPreference/Android.bp
+++ b/packages/SettingsLib/MainSwitchPreference/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_library {
name: "SettingsLibMainSwitchPreference",
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml
index 52779bcabf00..85c01c5732ca 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml
@@ -19,6 +19,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
+ android:background="?android:attr/colorBackground"
android:orientation="vertical">
<LinearLayout
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
index 74b65780ffc2..1c9298ed6085 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
@@ -17,6 +17,7 @@
package com.android.settingslib.widget;
import android.content.Context;
+import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
@@ -29,6 +30,7 @@ import android.widget.Switch;
import android.widget.TextView;
import androidx.annotation.VisibleForTesting;
+import androidx.core.content.res.TypedArrayUtils;
import com.android.settingslib.RestrictedLockUtils;
@@ -88,6 +90,17 @@ public class MainSwitchBar extends LinearLayout implements CompoundButton.OnChec
});
setChecked(mSwitch.isChecked());
+
+ if (attrs != null) {
+ final TypedArray a = context.obtainStyledAttributes(attrs,
+ androidx.preference.R.styleable.Preference, 0 /*defStyleAttr*/,
+ 0 /*defStyleRes*/);
+ final CharSequence title = TypedArrayUtils.getText(a,
+ androidx.preference.R.styleable.Preference_title,
+ androidx.preference.R.styleable.Preference_android_title);
+ setTitle(title);
+ a.recycle();
+ }
}
@Override
@@ -126,7 +139,7 @@ public class MainSwitchBar extends LinearLayout implements CompoundButton.OnChec
/**
* Set the title text
*/
- public void setTitle(String text) {
+ public void setTitle(CharSequence text) {
if (mTextView != null) {
mTextView.setText(text);
}
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
index 274bf8df2222..35afec38dd3d 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
@@ -18,7 +18,6 @@ package com.android.settingslib.widget;
import android.content.Context;
import android.content.res.TypedArray;
-import android.text.TextUtils;
import android.util.AttributeSet;
import androidx.core.content.res.TypedArrayUtils;
@@ -40,7 +39,7 @@ public class MainSwitchPreference extends TwoStatePreference {
private final List<OnMainSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>();
private MainSwitchBar mMainSwitchBar;
- private String mTitle;
+ private CharSequence mTitle;
private RestrictedLockUtils.EnforcedAdmin mEnforcedAdmin;
@@ -81,24 +80,28 @@ public class MainSwitchPreference extends TwoStatePreference {
setLayoutResource(R.layout.main_switch_layout);
if (attrs != null) {
- TypedArray a = context.obtainStyledAttributes(attrs,
+ final TypedArray a = context.obtainStyledAttributes(attrs,
androidx.preference.R.styleable.Preference, 0 /*defStyleAttr*/,
0 /*defStyleRes*/);
final CharSequence title = TypedArrayUtils.getText(a,
androidx.preference.R.styleable.Preference_title,
androidx.preference.R.styleable.Preference_android_title);
- if (!TextUtils.isEmpty(title)) {
- setTitle(title.toString());
- }
+ setTitle(title);
a.recycle();
}
}
- /**
- * Set the preference title text
- */
- public void setTitle(String text) {
- mTitle = text;
+ @Override
+ public void setChecked(boolean checked) {
+ super.setChecked(checked);
+ if (mMainSwitchBar != null) {
+ mMainSwitchBar.setChecked(checked);
+ }
+ }
+
+ @Override
+ public void setTitle(CharSequence title) {
+ mTitle = title;
if (mMainSwitchBar != null) {
mMainSwitchBar.setTitle(mTitle);
}
diff --git a/packages/SettingsLib/TopIntroPreference/Android.bp b/packages/SettingsLib/TopIntroPreference/Android.bp
index 03becbd23226..957728120c4d 100644
--- a/packages/SettingsLib/TopIntroPreference/Android.bp
+++ b/packages/SettingsLib/TopIntroPreference/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_library {
name: "SettingsLibTopIntroPreference",
diff --git a/packages/SettingsLib/UsageProgressBarPreference/Android.bp b/packages/SettingsLib/UsageProgressBarPreference/Android.bp
index 3331550d0535..ad6e7ab9f564 100644
--- a/packages/SettingsLib/UsageProgressBarPreference/Android.bp
+++ b/packages/SettingsLib/UsageProgressBarPreference/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_library {
name: "SettingsLibUsageProgressBarPreference",
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 4c80b91f300d..5e2d21b2e188 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -851,11 +851,12 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
if (BluetoothUuid.containsAnyUuid(uuids, PbapServerProfile.PBAB_CLIENT_UUIDS)) {
// The pairing dialog now warns of phone-book access for paired devices.
// No separate prompt is displayed after pairing.
+ final BluetoothClass bluetoothClass = mDevice.getBluetoothClass();
if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) {
- if (mDevice.getBluetoothClass().getDeviceClass()
- == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE ||
- mDevice.getBluetoothClass().getDeviceClass()
- == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET) {
+ if (bluetoothClass != null && (bluetoothClass.getDeviceClass()
+ == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE
+ || bluetoothClass.getDeviceClass()
+ == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET)) {
EventLog.writeEvent(0x534e4554, "138529441", -1, "");
}
mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 32419f49d8c9..1f3e0e9fe038 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -205,7 +205,6 @@ public class LocalMediaManager implements BluetoothCallback {
void dispatchDeviceListUpdate() {
final List<MediaDevice> mediaDevices = new ArrayList<>(mMediaDevices);
- Collections.sort(mediaDevices, COMPARATOR);
for (DeviceCallback callback : getCallbacks()) {
callback.onDeviceListUpdate(mediaDevices);
}
@@ -472,6 +471,7 @@ public class LocalMediaManager implements BluetoothCallback {
synchronized (mMediaDevicesLock) {
mMediaDevices.clear();
mMediaDevices.addAll(devices);
+ Collections.sort(devices, COMPARATOR);
// Add disconnected bluetooth devices only when phone output device is available.
for (MediaDevice device : devices) {
final int type = device.getDeviceType();
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java
index 647fd2acf7c8..552fa11a42b7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java
@@ -39,8 +39,7 @@ public class MediaOutputConstants {
/**
* A string extra specifying a media package name.
*/
- public static final String EXTRA_PACKAGE_NAME =
- "com.android.settings.panel.extra.PACKAGE_NAME";
+ public static final String EXTRA_PACKAGE_NAME = "package_name";
/**
* An intent action to launch media output dialog.
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 53ff1a10b6ff..53a99ab8cbe4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -27,12 +27,14 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.media.AudioManager;
import com.android.settingslib.R;
+import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
import org.junit.Before;
import org.junit.Test;
@@ -41,8 +43,11 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
public class CachedBluetoothDeviceTest {
private static final String DEVICE_NAME = "TestName";
private static final String DEVICE_ALIAS = "TestAlias";
@@ -72,12 +77,14 @@ public class CachedBluetoothDeviceTest {
private AudioManager mAudioManager;
private Context mContext;
private int mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+ private ShadowBluetoothAdapter mShadowBluetoothAdapter;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mAudioManager = mContext.getSystemService(AudioManager.class);
+ mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
when(mDevice.getAddress()).thenReturn(DEVICE_ADDRESS);
when(mHfpProfile.isProfileReady()).thenReturn(true);
when(mA2dpProfile.isProfileReady()).thenReturn(true);
@@ -937,4 +944,17 @@ public class CachedBluetoothDeviceTest {
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
mContext.getString(R.string.profile_connect_timeout_subtext));
}
+
+ @Test
+ public void onUuidChanged_bluetoothClassIsNull_shouldNotCrash() {
+ mShadowBluetoothAdapter.setUuids(PbapServerProfile.PBAB_CLIENT_UUIDS);
+ when(mDevice.getUuids()).thenReturn(PbapServerProfile.PBAB_CLIENT_UUIDS);
+ when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mDevice.getPhonebookAccessPermission()).thenReturn(BluetoothDevice.ACCESS_UNKNOWN);
+ when(mDevice.getBluetoothClass()).thenReturn(null);
+
+ mCachedDevice.onUuidChanged();
+
+ // Should not crash
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java
index b265d46058be..3b7fbc73522f 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java
@@ -24,6 +24,7 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
+import android.os.ParcelUuid;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@@ -36,6 +37,7 @@ public class ShadowBluetoothAdapter extends org.robolectric.shadows.ShadowBlueto
private List<Integer> mSupportedProfiles;
private List<BluetoothDevice> mMostRecentlyConnectedDevices;
private BluetoothProfile.ServiceListener mServiceListener;
+ private ParcelUuid[] mParcelUuids;
@Implementation
protected boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
@@ -87,4 +89,13 @@ public class ShadowBluetoothAdapter extends org.robolectric.shadows.ShadowBlueto
}
return true;
}
+
+ @Implementation
+ protected ParcelUuid[] getUuids() {
+ return mParcelUuids;
+ }
+
+ public void setUuids(ParcelUuid[] uuids) {
+ mParcelUuids = uuids;
+ }
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index ad6a5312f156..66165b6d1ff2 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -147,10 +147,5 @@ public class GlobalSettingsValidators {
VALIDATORS.put(Global.DEVELOPMENT_SETTINGS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.NOTIFICATION_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.RESTRICTED_NETWORKING_MODE, BOOLEAN_VALIDATOR);
- VALIDATORS.put(
- Global.ONE_HANDED_KEYGUARD_SIDE,
- new InclusiveIntegerRangeValidator(
- /* first= */Global.ONE_HANDED_KEYGUARD_SIDE_LEFT,
- /* last= */Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT));
}
}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index d715832dfca0..664fd4ac2fcb 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -283,7 +283,6 @@ public class SettingsBackupTest {
Settings.Global.EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS,
Settings.Global.EUICC_SWITCH_SLOT_TIMEOUT_MILLIS,
Settings.Global.FANCY_IME_ANIMATIONS,
- Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
Settings.Global.FORCED_APP_STANDBY_ENABLED,
Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
@@ -299,7 +298,6 @@ public class SettingsBackupTest {
Settings.Global.GNSS_SATELLITE_BLOCKLIST,
Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
Settings.Global.HDMI_CEC_SWITCH_ENABLED,
- Settings.Global.HDMI_CEC_VERSION,
Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
Settings.Global.HDMI_CONTROL_ENABLED,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 259484073162..7ced202c5e44 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -125,6 +125,8 @@
<uses-permission android:name="android.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP" />
<uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
<uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
+ <uses-permission android:name="android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS" />
+ <uses-permission android:name="android.permission.CLEAR_FREEZE_PERIOD" />
<uses-permission android:name="android.permission.QUERY_USERS" />
<uses-permission android:name="android.permission.MODIFY_QUIET_MODE" />
<uses-permission android:name="android.permission.ACCESS_LOWPAN_STATE"/>
diff --git a/packages/Shell/OWNERS b/packages/Shell/OWNERS
index 34901f5830c4..6d738f8d4d43 100644
--- a/packages/Shell/OWNERS
+++ b/packages/Shell/OWNERS
@@ -9,3 +9,4 @@ yamasani@google.com
toddke@google.com
cbrubaker@google.com
omakoto@google.com
+michaelwr@google.com
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
index 71cdaf5c7091..79868093fb12 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
@@ -24,7 +24,7 @@
<include
style="@style/BouncerSecurityContainer"
layout="@layout/keyguard_host_view"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
index c75ee51517d1..04e645bd0a32 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
@@ -41,14 +41,13 @@
android:layout_gravity="center">
<com.android.keyguard.KeyguardSecurityViewFlipper
android:id="@+id/view_flipper"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingTop="@dimen/keyguard_security_view_top_margin"
android:paddingStart="@dimen/keyguard_security_view_lateral_margin"
android:paddingEnd="@dimen/keyguard_security_view_lateral_margin"
- android:layout_gravity="center"
android:gravity="center">
</com.android.keyguard.KeyguardSecurityViewFlipper>
</com.android.keyguard.KeyguardSecurityContainer>
diff --git a/packages/SystemUI/res-keyguard/values/config.xml b/packages/SystemUI/res-keyguard/values/config.xml
index 6176f7c1dd0a..8d9d6ee68c67 100644
--- a/packages/SystemUI/res-keyguard/values/config.xml
+++ b/packages/SystemUI/res-keyguard/values/config.xml
@@ -22,5 +22,4 @@
<!-- Allow the menu hard key to be disabled in LockScreen on some devices [DO NOT TRANSLATE] -->
<bool name="config_disableMenuKeyInLockScreen">false</bool>
- <bool name="can_use_one_handed_bouncer">false</bool>
</resources>
diff --git a/packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml b/packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml
index d097472471b0..8efe0539207a 100644
--- a/packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml
+++ b/packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml
@@ -41,8 +41,10 @@
</item>
<item android:id="@android:id/progress"
android:gravity="center_vertical|fill_horizontal">
- <com.android.systemui.util.RoundedCornerProgressDrawable
+ <clip
android:drawable="@drawable/brightness_progress_full_drawable"
+ android:clipOrientation="horizontal"
+ android:gravity="left"
/>
</item>
</layer-list> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
index 41140a7a8c85..5bc2773dc657 100644
--- a/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
+++ b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
@@ -26,10 +26,10 @@
</item>
<item
android:id="@+id/slider_icon"
- android:gravity="center_vertical|right"
+ android:gravity="center_vertical|left"
android:height="@dimen/rounded_slider_icon_size"
android:width="@dimen/rounded_slider_icon_size"
- android:right="@dimen/rounded_slider_icon_inset">
+ android:left="@dimen/rounded_slider_icon_inset">
<com.android.systemui.util.AlphaTintDrawableWrapper
android:drawable="@drawable/ic_brightness"
android:tint="?android:attr/colorBackground"
diff --git a/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml b/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml
index 9f66581d8053..96e01934e670 100644
--- a/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml
+++ b/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml
@@ -36,8 +36,4 @@
</vector>
</item>
- <item>
- <ripple android:color="@color/GM2_grey_600"></ripple>
- </item>
-
</layer-list>
diff --git a/packages/SystemUI/res/drawable/ic_open_in_new_window.xml b/packages/SystemUI/res/drawable/ic_open_in_new_window.xml
index 659b02048c73..368c8dfb5023 100644
--- a/packages/SystemUI/res/drawable/ic_open_in_new_window.xml
+++ b/packages/SystemUI/res/drawable/ic_open_in_new_window.xml
@@ -50,28 +50,7 @@
android:strokeWidth="1"
android:pathData="M 12.5 13.92 L 15.59 17 L 17 15.59 L 13.91 12.5 L 16.5 12.5 L 16.5 10.5 L 10.5 10.5 L 10.5 16.5 L 12.5 16.5 Z" />
</group>
- <group
- android:translateX="22.000000"
- android:translateY="2.000000">
- <group
- android:translateX="3.000000"
- android:translateY="3.000000">
- <group
- android:translateX="-3.000000"
- android:translateY="-3.000000">
- <path
- android:fillColor="#80868B"
- android:fillType="evenOdd"
- android:strokeWidth="1"
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- </group>
- </group>
- </group>
</vector>
</item>
- <item>
- <ripple android:color="@color/GM2_grey_600"></ripple>
- </item>
-
</layer-list>
diff --git a/packages/SystemUI/res/drawable/ic_phone_missed.xml b/packages/SystemUI/res/drawable/ic_phone_missed.xml
new file mode 100644
index 000000000000..72e67d4a2ed0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_phone_missed.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M6.5,5.5L12,11l7,-7 -1,-1 -6,6 -4.5,-4.5L11,4.5L11,3L5,3v6h1.5L6.5,5.5zM23.71,16.67C20.66,13.78 16.54,12 12,12 7.46,12 3.34,13.78 0.29,16.67c-0.18,0.18 -0.29,0.43 -0.29,0.71s0.11,0.53 0.29,0.71l2.48,2.48c0.18,0.18 0.43,0.29 0.71,0.29 0.27,0 0.52,-0.11 0.7,-0.28 0.79,-0.74 1.69,-1.36 2.66,-1.85 0.33,-0.16 0.56,-0.5 0.56,-0.9v-3.1c1.45,-0.48 3,-0.73 4.6,-0.73 1.6,0 3.15,0.25 4.6,0.72v3.1c0,0.39 0.23,0.74 0.56,0.9 0.98,0.49 1.87,1.12 2.67,1.85 0.18,0.18 0.43,0.28 0.7,0.28 0.28,0 0.53,-0.11 0.71,-0.29l2.48,-2.48c0.18,-0.18 0.29,-0.43 0.29,-0.71s-0.12,-0.52 -0.3,-0.7z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/people_space_content_background.xml b/packages/SystemUI/res/drawable/people_space_content_background.xml
index 32314d29277e..30519aeddb45 100644
--- a/packages/SystemUI/res/drawable/people_space_content_background.xml
+++ b/packages/SystemUI/res/drawable/people_space_content_background.xml
@@ -15,6 +15,6 @@
~ limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
- <solid android:color="?android:attr/colorControlHighlight" />
+ <solid android:color="?android:attr/colorBackground" />
<corners android:radius="@dimen/people_space_image_radius" />
</shape>
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index 73beefc9da83..d996cee4b39e 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -32,7 +32,8 @@
android:id="@+id/header_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingEnd="@dimen/media_output_dialog_header_icon_padding"/>
+ android:paddingEnd="@dimen/media_output_dialog_header_icon_padding"
+ android:importantForAccessibility="no"/>
<LinearLayout
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 23f34251b812..4ca59f5082ad 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -37,12 +37,6 @@
android:layout_height="match_parent"
android:layout_width="match_parent" />
- <ViewStub
- android:id="@+id/keyguard_user_switcher_stub"
- android:layout="@layout/keyguard_user_switcher"
- android:layout_height="match_parent"
- android:layout_width="match_parent" />
-
<include
layout="@layout/keyguard_status_view"
android:visibility="gone" />
@@ -109,5 +103,11 @@
layout="@layout/keyguard_bottom_area"
android:visibility="gone" />
+ <ViewStub
+ android:id="@+id/keyguard_user_switcher_stub"
+ android:layout="@layout/keyguard_user_switcher"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent" />
+
<include layout="@layout/status_bar_expanded_plugin_frame"/>
</com.android.systemui.statusbar.phone.NotificationPanelView>
diff --git a/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml b/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml
deleted file mode 100644
index b62018d7cb9e..000000000000
--- a/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:padding="12dp">
-
- <FrameLayout
- android:layout_width="34dp"
- android:layout_height="24dp"
- android:layout_gravity="center"
- android:background="@drawable/tv_rect_shadow_rounded">
-
- <ImageView
- android:layout_width="13dp"
- android:layout_height="13dp"
- android:layout_gravity="center"
- android:src="@drawable/tv_ic_mic_white"/>
-
- </FrameLayout>
-
-</LinearLayout>
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml b/packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml
index e09bf7e37ed0..dff148b2c570 100644
--- a/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml
+++ b/packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2021 The Android Open Source Project
+ ~ 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.
@@ -15,6 +15,21 @@
~ limitations under the License.
-->
-<resources>
- <bool name="can_use_one_handed_bouncer">true</bool>
-</resources>
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="12dp"
+ android:layout_gravity="center">
+
+ <LinearLayout
+ android:id="@+id/icons_container"
+ android:background="@drawable/tv_rect_shadow_rounded"
+ android:padding="@dimen/privacy_chip_icon_padding"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"/>
+
+</FrameLayout>
+
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index 722f1480463d..b02d8b8cf7e4 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -28,6 +28,7 @@
<string-array name="config_systemUIServiceComponents" translatable="false">
<item>com.android.systemui.util.NotificationChannels</item>
<item>com.android.systemui.volume.VolumeUI</item>
+ <item>com.android.systemui.privacy.television.TvOngoingPrivacyChip</item>
<item>com.android.systemui.statusbar.tv.TvStatusBar</item>
<item>com.android.systemui.statusbar.tv.notifications.TvNotificationPanel</item>
<item>com.android.systemui.statusbar.tv.notifications.TvNotificationHandler</item>
diff --git a/packages/SystemUI/res/values-television/dimens.xml b/packages/SystemUI/res/values-television/dimens.xml
index 6da0c693f389..7626db93dd76 100644
--- a/packages/SystemUI/res/values-television/dimens.xml
+++ b/packages/SystemUI/res/values-television/dimens.xml
@@ -17,4 +17,8 @@
<resources>
<!-- Opacity at which the background for the shutdown UI will be drawn. -->
<item name="shutdown_scrim_behind_alpha" format="float" type="dimen">1.0</item>
+
+ <dimen name="privacy_chip_icon_margin">3dp</dimen>
+ <dimen name="privacy_chip_icon_padding">8dp</dimen>
+ <dimen name="privacy_chip_icon_size">13dp</dimen>
</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 6e458681bbab..be49e1f8c71e 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -170,7 +170,6 @@
<declare-styleable name="AlphaTintDrawableWrapper">
<attr name="android:tint" />
- <attr name="android:drawable" />
<attr name="android:alpha" />
</declare-styleable>
@@ -191,9 +190,5 @@
<attr name="borderThickness" format="dimension" />
<attr name="borderColor" format="color" />
</declare-styleable>
-
- <declare-styleable name="RoundedCornerProgressDrawable">
- <attr name="android:drawable" />
- </declare-styleable>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 13c01102d032..f13fdd34e4f3 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -421,6 +421,9 @@
vibrator is capable of subtle vibrations -->
<bool name="config_vibrateOnIconAnimation">false</bool>
+ <!-- Adjust the theme on fully custom and decorated custom view notifications -->
+ <bool name="config_adjustThemeOnNotificationCustomViews">false</bool>
+
<!-- If true, enable the advance anti-falsing classifier on the lockscreen. On some devices it
does not work well, particularly with noisy touchscreens. Note that disabling it may
increase the rate of unintentional unlocks. -->
@@ -574,4 +577,7 @@
<!-- Whether to use the split 2-column notification shade -->
<bool name="config_use_split_notification_shade">false</bool>
+
+ <!-- Determines whether the shell features all run on another thread. -->
+ <bool name="config_enableShellMainThread">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/config_tv.xml b/packages/SystemUI/res/values/config_tv.xml
deleted file mode 100644
index 2e776749582c..000000000000
--- a/packages/SystemUI/res/values/config_tv.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<resources>
- <!-- Whether to enable microphone disclosure indicator
- (com.android.systemui.statusbar.tv.micdisclosure.AudioRecordingDisclosureBar). -->
- <bool name="audio_recording_disclosure_enabled">true</bool>
-</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 4bc5a300e833..89c849a0ef4a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -651,7 +651,7 @@
</dimen>
<!-- The height of a notification header -->
- <dimen name="notification_header_height">53dp</dimen>
+ <dimen name="notification_header_height">@*android:dimen/notification_header_height</dimen>
<!-- The height of the gap between adjacent notification sections. -->
<dimen name="notification_section_divider_height">@dimen/notification_side_paddings</dimen>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index d4bb128120e9..3e16cd47336c 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -42,4 +42,6 @@
<bool name="flag_lockscreen_animations">false</bool>
<bool name="flag_toast_style">false</bool>
+
+ <bool name="flag_navigation_bar_overlay">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 70e8b8946ae6..4b95c16a3602 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2840,6 +2840,8 @@
<string name="empty_user_name" translatable="false">Your friend</string>
<!-- Empty status shown before user has selected a friend [CHAR LIMIT=30] -->
<string name="empty_status" translatable="false">Their status</string>
+ <!-- Default text for missed call notifications [CHAR LIMIT=30] -->
+ <string name="missed_call" translatable="false">Missed call</string>
<!-- Title to display in a notification when ACTION_BATTERY_CHANGED.EXTRA_PRESENT field is false
[CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index d2698ee9fe3b..b3a29a3fec78 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -190,7 +190,7 @@ public class TaskStackChangeListeners {
}
@Override
- public void onActivityDismissingDockedStack() {
+ public void onActivityDismissingDockedTask() {
mHandler.sendEmptyMessage(ON_ACTIVITY_DISMISSING_DOCKED_STACK);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index f511ed1c69c4..5f6fd30ffa1b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -29,17 +29,12 @@ import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Rect;
-import android.provider.Settings;
import android.util.AttributeSet;
import android.util.MathUtils;
import android.util.TypedValue;
-import android.view.Gravity;
import android.view.MotionEvent;
-import android.view.OrientationEventListener;
import android.view.VelocityTracker;
-import android.view.View;
import android.view.ViewConfiguration;
-import android.view.ViewPropertyAnimator;
import android.view.WindowInsets;
import android.view.WindowInsetsAnimation;
import android.view.WindowInsetsAnimationControlListener;
@@ -60,7 +55,6 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import java.util.List;
@@ -105,12 +99,6 @@ public class KeyguardSecurityContainer extends FrameLayout {
private boolean mDisappearAnimRunning;
private SwipeListener mSwipeListener;
- private boolean mIsSecurityViewLeftAligned = true;
- private boolean mOneHandedMode = false;
- private SecurityMode mSecurityMode = SecurityMode.Invalid;
- private ViewPropertyAnimator mRunningOneHandedAnimator;
- private final OrientationEventListener mOrientationEventListener;
-
private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
@@ -169,20 +157,16 @@ public class KeyguardSecurityContainer extends FrameLayout {
// Used to notify the container when something interesting happens.
public interface SecurityCallback {
boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen);
-
void userActivity();
-
void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
/**
- * @param strongAuth wheher the user has authenticated with strong authentication like
- * pattern, password or PIN but not by trust agents or fingerprint
+ * @param strongAuth wheher the user has authenticated with strong authentication like
+ * pattern, password or PIN but not by trust agents or fingerprint
* @param targetUserId a user that needs to be the foreground user at the finish completion.
*/
void finish(boolean strongAuth, int targetUserId);
-
void reset();
-
void onCancelClicked();
}
@@ -240,136 +224,12 @@ public class KeyguardSecurityContainer extends FrameLayout {
super(context, attrs, defStyle);
mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y);
mViewConfiguration = ViewConfiguration.get(context);
-
- mOrientationEventListener = new OrientationEventListener(context) {
- @Override
- public void onOrientationChanged(int orientation) {
- updateLayoutForSecurityMode(mSecurityMode);
- }
- };
}
void onResume(SecurityMode securityMode, boolean faceAuthEnabled) {
- mSecurityMode = securityMode;
mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback);
updateBiometricRetry(securityMode, faceAuthEnabled);
- updateLayoutForSecurityMode(securityMode);
- mOrientationEventListener.enable();
- }
-
- void updateLayoutForSecurityMode(SecurityMode securityMode) {
- mSecurityMode = securityMode;
- mOneHandedMode = canUseOneHandedBouncer();
-
- if (mOneHandedMode) {
- mIsSecurityViewLeftAligned = isOneHandedKeyguardLeftAligned(mContext);
- }
-
- updateSecurityViewGravity();
- updateSecurityViewLocation(false);
- }
-
- /** Return whether the one-handed keyguard should be enabled. */
- private boolean canUseOneHandedBouncer() {
- // Is it enabled?
- if (!getResources().getBoolean(
- com.android.internal.R.bool.config_enableOneHandedKeyguard)) {
- return false;
- }
-
- if (!KeyguardSecurityModel.isSecurityViewOneHanded(mSecurityMode)) {
- return false;
- }
-
- return getResources().getBoolean(R.bool.can_use_one_handed_bouncer);
- }
-
- /** Read whether the one-handed keyguard should be on the left/right from settings. */
- private boolean isOneHandedKeyguardLeftAligned(Context context) {
- try {
- return Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.ONE_HANDED_KEYGUARD_SIDE)
- == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT;
- } catch (Settings.SettingNotFoundException ex) {
- return true;
- }
- }
-
- private void updateSecurityViewGravity() {
- View securityView = findKeyguardSecurityView();
-
- if (securityView == null) {
- return;
- }
-
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) securityView.getLayoutParams();
-
- if (mOneHandedMode) {
- lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
- } else {
- lp.gravity = Gravity.CENTER_HORIZONTAL;
- }
-
- securityView.setLayoutParams(lp);
- }
-
- /**
- * Moves the inner security view to the correct location (in one handed mode) with animation.
- * This is triggered when the user taps on the side of the screen that is not currently occupied
- * by the security view .
- */
- private void updateSecurityViewLocation(boolean animate) {
- View securityView = findKeyguardSecurityView();
-
- if (securityView == null) {
- return;
- }
-
- if (!mOneHandedMode) {
- securityView.setTranslationX(0);
- return;
- }
-
- if (mRunningOneHandedAnimator != null) {
- mRunningOneHandedAnimator.cancel();
- mRunningOneHandedAnimator = null;
- }
-
- int targetTranslation = mIsSecurityViewLeftAligned ? 0 : (int) (getMeasuredWidth() / 2f);
-
- if (animate) {
- mRunningOneHandedAnimator = securityView.animate().translationX(targetTranslation);
- mRunningOneHandedAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- mRunningOneHandedAnimator.setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mRunningOneHandedAnimator = null;
- }
- });
-
- mRunningOneHandedAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- mRunningOneHandedAnimator.start();
- } else {
- securityView.setTranslationX(targetTranslation);
- }
- }
-
- @Nullable
- private KeyguardSecurityViewFlipper findKeyguardSecurityView() {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
-
- if (isKeyguardSecurityView(child)) {
- return (KeyguardSecurityViewFlipper) child;
- }
- }
-
- return null;
- }
-
- private boolean isKeyguardSecurityView(View view) {
- return view instanceof KeyguardSecurityViewFlipper;
}
public void onPause() {
@@ -378,7 +238,6 @@ public class KeyguardSecurityContainer extends FrameLayout {
mAlertDialog = null;
}
mSecurityViewFlipper.setWindowInsetsAnimationCallback(null);
- mOrientationEventListener.disable();
}
@Override
@@ -460,44 +319,19 @@ public class KeyguardSecurityContainer extends FrameLayout {
if (mSwipeListener != null) {
mSwipeListener.onSwipeUp();
}
- } else {
- if (!mIsDragging) {
- handleTap(event);
- }
}
}
return true;
}
- private void handleTap(MotionEvent event) {
- // If we're using a fullscreen security mode, skip
- if (!mOneHandedMode) {
- return;
- }
-
- // Did the tap hit the "other" side of the bouncer?
- if ((mIsSecurityViewLeftAligned && (event.getX() > getWidth() / 2f))
- || (!mIsSecurityViewLeftAligned && (event.getX() < getWidth() / 2f))) {
- mIsSecurityViewLeftAligned = !mIsSecurityViewLeftAligned;
-
- Settings.Global.putInt(
- mContext.getContentResolver(),
- Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
- mIsSecurityViewLeftAligned ? Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT
- : Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT);
-
- updateSecurityViewLocation(true);
- }
- }
-
void setSwipeListener(SwipeListener swipeListener) {
mSwipeListener = swipeListener;
}
private void startSpringAnimation(float startVelocity) {
mSpringAnimation
- .setStartVelocity(startVelocity)
- .animateToFinalPosition(0);
+ .setStartVelocity(startVelocity)
+ .animateToFinalPosition(0);
}
public void startDisappearAnimation(SecurityMode securitySelection) {
@@ -607,17 +441,18 @@ public class KeyguardSecurityContainer extends FrameLayout {
return insets.inset(0, 0, 0, inset);
}
+
private void showDialog(String title, String message) {
if (mAlertDialog != null) {
mAlertDialog.dismiss();
}
mAlertDialog = new AlertDialog.Builder(mContext)
- .setTitle(title)
- .setMessage(message)
- .setCancelable(false)
- .setNeutralButton(R.string.ok, null)
- .create();
+ .setTitle(title)
+ .setMessage(message)
+ .setCancelable(false)
+ .setNeutralButton(R.string.ok, null)
+ .create();
if (!(mContext instanceof Activity)) {
mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
}
@@ -655,44 +490,6 @@ public class KeyguardSecurityContainer extends FrameLayout {
}
}
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int maxHeight = 0;
- int maxWidth = 0;
- int childState = 0;
-
- int halfWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
- MeasureSpec.getSize(widthMeasureSpec) / 2,
- MeasureSpec.getMode(widthMeasureSpec));
-
- for (int i = 0; i < getChildCount(); i++) {
- final View view = getChildAt(i);
- if (view.getVisibility() != GONE) {
- if (mOneHandedMode && isKeyguardSecurityView(view)) {
- measureChildWithMargins(view, halfWidthMeasureSpec, 0,
- heightMeasureSpec, 0);
- } else {
- measureChildWithMargins(view, widthMeasureSpec, 0,
- heightMeasureSpec, 0);
- }
- final LayoutParams lp = (LayoutParams) view.getLayoutParams();
- maxWidth = Math.max(maxWidth,
- view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
- maxHeight = Math.max(maxHeight,
- view.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
- childState = combineMeasuredStates(childState, view.getMeasuredState());
- }
- }
-
- // Check against our minimum height and width
- maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
- maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
-
- setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
- resolveSizeAndState(maxHeight, heightMeasureSpec,
- childState << MEASURED_HEIGHT_STATE_SHIFT));
- }
-
void showAlmostAtWipeDialog(int attempts, int remaining, int userType) {
String message = null;
switch (userType) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index fdab8db67431..1a8d420fb394 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -404,7 +404,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
if (newView != null) {
newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
mSecurityViewFlipperController.show(newView);
- mView.updateLayoutForSecurityMode(securityMode);
}
mSecurityCallback.onSecurityModeChanged(
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
index 631c24844417..c77c86711abf 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -92,13 +92,4 @@ public class KeyguardSecurityModel {
throw new IllegalStateException("Unknown security quality:" + security);
}
}
-
- /**
- * Returns whether the given security view should be used in a "one handed" way. This can be
- * used to change how the security view is drawn (e.g. take up less of the screen, and align to
- * one side).
- */
- public static boolean isSecurityViewOneHanded(SecurityMode securityMode) {
- return securityMode == SecurityMode.Pattern || securityMode == SecurityMode.PIN;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index ec3188a6144f..5d226d562c29 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -29,6 +29,7 @@ import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.media.systemsounds.HomeSoundEffectController;
import com.android.systemui.people.widget.PeopleSpaceWidgetEnabler;
import com.android.systemui.power.PowerUI;
+import com.android.systemui.privacy.television.TvOngoingPrivacyChip;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsModule;
import com.android.systemui.shortcut.ShortcutKeyDispatcher;
@@ -155,6 +156,12 @@ public abstract class SystemUIBinder {
@ClassKey(TvNotificationPanel.class)
public abstract SystemUI bindsTvNotificationPanel(TvNotificationPanel sysui);
+ /** Inject into TvOngoingPrivacyChip. */
+ @Binds
+ @IntoMap
+ @ClassKey(TvOngoingPrivacyChip.class)
+ public abstract SystemUI bindsTvOngoingPrivacyChip(TvOngoingPrivacyChip sysui);
+
/** Inject into VolumeUI. */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 27ea64f85b11..70b7b047eebc 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -25,7 +25,6 @@ import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;
import android.view.Display;
@@ -54,7 +53,6 @@ import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -116,7 +114,7 @@ public class NavigationBarController implements Callbacks,
// Tracks config changes that will actually recreate the nav bar
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE
- | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS
+ | ActivityInfo.CONFIG_SCREEN_LAYOUT
| ActivityInfo.CONFIG_UI_MODE);
@Inject
@@ -171,6 +169,7 @@ public class NavigationBarController implements Callbacks,
configurationController.addCallback(this);
mConfigChanges.applyNewConfig(mContext.getResources());
mNavBarOverlayController = navBarOverlayController;
+ mNavigationModeController.addListener(this);
}
@Override
@@ -188,17 +187,18 @@ public class NavigationBarController implements Callbacks,
@Override
public void onNavigationModeChanged(int mode) {
- // Workaround for b/132825155, for secondary users, we currently don't receive configuration
- // changes on overlay package change since SystemUI runs for the system user. In this case,
- // trigger a new configuration change to ensure that the nav bar is updated in the same way.
- int userId = ActivityManagerWrapper.getInstance().getCurrentUserId();
- if (userId != UserHandle.USER_SYSTEM) {
- mHandler.post(() -> {
- for (int i = 0; i < mNavigationBars.size(); i++) {
- recreateNavigationBar(mNavigationBars.keyAt(i));
+ mHandler.post(() -> {
+ for (int i = 0; i < mNavigationBars.size(); i++) {
+ NavigationBar navBar = mNavigationBars.valueAt(i);
+ if (navBar == null) {
+ continue;
}
- });
- }
+ NavigationBarView view = (NavigationBarView) mNavigationBars.get(i).getView();
+ if (view != null) {
+ view.updateStates();
+ }
+ }
+ });
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarOverlayController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarOverlayController.java
index c526c5d59552..62b9458447d8 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarOverlayController.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.view.View;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.statusbar.FeatureFlags;
import java.util.function.Consumer;
@@ -31,16 +32,22 @@ import javax.inject.Inject;
public class NavigationBarOverlayController {
protected final Context mContext;
+ protected final FeatureFlags mFeatureFlags;
@Inject
- public NavigationBarOverlayController(Context context) {
+ public NavigationBarOverlayController(Context context, FeatureFlags featureFlags) {
mContext = context;
+ mFeatureFlags = featureFlags;
}
public Context getContext() {
return mContext;
}
+ public boolean isNavigationBarOverlayEnabled() {
+ return mFeatureFlags.isNavigationBarOverlayEnabled();
+ }
+
/**
* Initialize the controller with visibility change callback and light/dark icon color.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
index b55fa4d612f9..61e1d61e7909 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
@@ -192,6 +192,7 @@ public final class NavigationBarTransitions extends BarTransitions implements
buttonDispatchers.valueAt(i).setDarkIntensity(darkIntensity);
}
mView.getRotationButtonController().setDarkIntensity(darkIntensity);
+
Dependency.get(NavigationBarOverlayController.class).setDarkIntensity(darkIntensity);
for (DarkIntensityListener listener : mDarkIntensityListeners) {
listener.onDarkIntensity(darkIntensity);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 8e75bec72c15..19e32783f765 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -171,6 +171,7 @@ public class NavigationBarView extends FrameLayout implements
private NotificationPanelViewController mPanelView;
private FloatingRotationButton mFloatingRotationButton;
private RotationButtonController mRotationButtonController;
+ private NavigationBarOverlayController mNavBarOverlayController;
/**
* Helper that is responsible for showing the right toast when a disallowed activity operation
@@ -339,8 +340,11 @@ public class NavigationBarView extends FrameLayout implements
isGesturalMode ? mFloatingRotationButton : rotateSuggestionButton,
mRotationButtonListener);
- Dependency.get(NavigationBarOverlayController.class).init(
- mNavbarOverlayVisibilityChangeCallback, mLightIconColor, mDarkIconColor);
+ mNavBarOverlayController = Dependency.get(NavigationBarOverlayController.class);
+ if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) {
+ mNavBarOverlayController.init(
+ mNavbarOverlayVisibilityChangeCallback, mLightIconColor, mDarkIconColor);
+ }
mConfiguration = new Configuration();
mTmpLastConfiguration = new Configuration();
@@ -431,8 +435,9 @@ public class NavigationBarView extends FrameLayout implements
// The visibility of the navigation bar buttons is dependent on the transient state of
// the navigation bar.
- Dependency.get(NavigationBarOverlayController.class).setButtonState(
- isTransient, /* force */ false);
+ if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) {
+ mNavBarOverlayController.setButtonState(isTransient, /* force */ false);
+ }
}
void onBarTransition(int newMode) {
@@ -666,7 +671,9 @@ public class NavigationBarView extends FrameLayout implements
}
mImeVisible = visible;
mRotationButtonController.getRotationButton().setCanShowRotationButton(!mImeVisible);
- Dependency.get(NavigationBarOverlayController.class).setCanShow(!mImeVisible);
+ if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) {
+ mNavBarOverlayController.setCanShow(!mImeVisible);
+ }
}
public void setDisabledFlags(int disabledFlags) {
@@ -999,10 +1006,9 @@ public class NavigationBarView extends FrameLayout implements
} else {
updateButtonLocation(getRotateSuggestionButton(), inScreenSpace);
}
- final NavigationBarOverlayController navBarButtonsController =
- Dependency.get(NavigationBarOverlayController.class);
- if (navBarButtonsController.isVisible()) {
- updateButtonLocation(navBarButtonsController.getCurrentView(), inScreenSpace);
+ if (mNavBarOverlayController.isNavigationBarOverlayEnabled()
+ && mNavBarOverlayController.isVisible()) {
+ updateButtonLocation(mNavBarOverlayController.getCurrentView(), inScreenSpace);
}
return mTmpRegion;
}
@@ -1230,7 +1236,9 @@ public class NavigationBarView extends FrameLayout implements
if (mRotationButtonController != null) {
mRotationButtonController.registerListeners();
}
- Dependency.get(NavigationBarOverlayController.class).registerListeners();
+ if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) {
+ mNavBarOverlayController.registerListeners();
+ }
getViewTreeObserver().addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
updateNavButtonIcons();
@@ -1247,7 +1255,10 @@ public class NavigationBarView extends FrameLayout implements
if (mRotationButtonController != null) {
mRotationButtonController.unregisterListeners();
}
- Dependency.get(NavigationBarOverlayController.class).unregisterListeners();
+
+ if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) {
+ mNavBarOverlayController.unregisterListeners();
+ }
mEdgeBackGestureHandler.onNavBarDetached();
getViewTreeObserver().removeOnComputeInternalInsetsListener(
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
index 65d4e23f7734..870e3bed2b7a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
@@ -132,7 +132,7 @@ public class NavigationModeController implements Dumpable {
Settings.Secure.putString(mCurrentUserContext.getContentResolver(),
Secure.NAVIGATION_MODE, String.valueOf(mode)));
if (DEBUG) {
- Log.e(TAG, "updateCurrentInteractionMode: mode=" + mode);
+ Log.d(TAG, "updateCurrentInteractionMode: mode=" + mode);
dumpAssetPaths(mCurrentUserContext);
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 292cc7a7deaa..088743cd0f94 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -93,6 +93,9 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
private static final int MAX_LONG_PRESS_TIMEOUT = SystemProperties.getInt(
"gestures.back_timeout", 250);
+ private static final int MAX_NUM_LOGGED_PREDICTIONS = 10;
+ private static final int MAX_NUM_LOGGED_GESTURES = 10;
+
// Temporary log until b/176302696 is resolved
static final boolean DEBUG_MISSING_GESTURE = true;
static final String DEBUG_MISSING_GESTURE_TAG = "NoBackGesture";
@@ -222,8 +225,9 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
private String mPackageName;
private float mMLResults;
- private static final int MAX_LOGGED_PREDICTIONS = 10;
+ // For debugging
private ArrayDeque<String> mPredictionLog = new ArrayDeque<>();
+ private ArrayDeque<String> mGestureLog = new ArrayDeque<>();
private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
@@ -607,7 +611,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
}
// Check if we are within the tightest bounds beyond which
// we would not need to run the ML model.
- boolean withinRange = x <= mMLEnableWidth + mLeftInset
+ boolean withinRange = x < mMLEnableWidth + mLeftInset
|| x >= (mDisplaySize.x - mMLEnableWidth - mRightInset);
if (!withinRange) {
int results = -1;
@@ -617,17 +621,20 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
// Denotes whether we should proceed with the gesture.
// Even if it is false, we may want to log it assuming
// it is not invalid due to exclusion.
- withinRange = x <= mEdgeWidthLeft + mLeftInset
+ withinRange = x < mEdgeWidthLeft + mLeftInset
|| x >= (mDisplaySize.x - mEdgeWidthRight - mRightInset);
}
}
// For debugging purposes
- if (mPredictionLog.size() >= MAX_LOGGED_PREDICTIONS) {
+ if (mPredictionLog.size() >= MAX_NUM_LOGGED_PREDICTIONS) {
mPredictionLog.removeFirst();
}
- mPredictionLog.addLast(String.format("[%d,%d,%d,%f,%d]",
- x, y, app, mMLResults, withinRange ? 1 : 0));
+ mPredictionLog.addLast(String.format("Prediction [%d,%d,%d,%d,%f,%d]",
+ System.currentTimeMillis(), x, y, app, mMLResults, withinRange ? 1 : 0));
+ if (DEBUG_MISSING_GESTURE) {
+ Log.d(DEBUG_MISSING_GESTURE_TAG, mPredictionLog.peekLast());
+ }
// Always allow if the user is in a transient sticky immersive state
if (mIsNavBarShownTransiently) {
@@ -689,6 +696,10 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
private void onMotionEvent(MotionEvent ev) {
int action = ev.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
+ if (DEBUG_MISSING_GESTURE) {
+ Log.d(DEBUG_MISSING_GESTURE_TAG, "Start gesture: " + ev);
+ }
+
// Verify if this is in within the touch region and we aren't in immersive mode, and
// either the bouncer is showing or the notification panel is hidden
mInputEventReceiver.setBatchingEnabled(false);
@@ -709,6 +720,19 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
mEndPoint.set(-1, -1);
mThresholdCrossed = false;
}
+
+ // For debugging purposes
+ if (mGestureLog.size() >= MAX_NUM_LOGGED_GESTURES) {
+ mGestureLog.removeFirst();
+ }
+ mGestureLog.addLast(String.format(
+ "Gesture [%d,alw=%B,%B, %B,%B,disp=%s,wl=%d,il=%d,wr=%d,ir=%d,excl=%s]",
+ System.currentTimeMillis(), mAllowGesture, mIsOnLeftEdge, mIsBackGestureAllowed,
+ QuickStepContract.isBackGestureDisabled(mSysUiFlags), mDisplaySize,
+ mEdgeWidthLeft, mLeftInset, mEdgeWidthRight, mRightInset, mExcludeRegion));
+ if (DEBUG_MISSING_GESTURE) {
+ Log.d(DEBUG_MISSING_GESTURE_TAG, mGestureLog.peekLast());
+ }
} else if (mAllowGesture || mLogGesture) {
if (!mThresholdCrossed) {
mEndPoint.x = (int) ev.getX();
@@ -827,18 +851,29 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
public void dump(PrintWriter pw) {
pw.println("EdgeBackGestureHandler:");
pw.println(" mIsEnabled=" + mIsEnabled);
+ pw.println(" mIsAttached=" + mIsAttached);
pw.println(" mIsBackGestureAllowed=" + mIsBackGestureAllowed);
+ pw.println(" mIsGesturalModeEnabled=" + mIsGesturalModeEnabled);
+ pw.println(" mIsNavBarShownTransiently=" + mIsNavBarShownTransiently);
+ pw.println(" mGestureBlockingActivityRunning=" + mGestureBlockingActivityRunning);
pw.println(" mAllowGesture=" + mAllowGesture);
+ pw.println(" mUseMLModel=" + mUseMLModel);
pw.println(" mDisabledForQuickstep=" + mDisabledForQuickstep);
pw.println(" mStartingQuickstepRotation=" + mStartingQuickstepRotation);
pw.println(" mInRejectedExclusion" + mInRejectedExclusion);
pw.println(" mExcludeRegion=" + mExcludeRegion);
pw.println(" mUnrestrictedExcludeRegion=" + mUnrestrictedExcludeRegion);
- pw.println(" mIsAttached=" + mIsAttached);
+ pw.println(" mPipExcludedBounds=" + mPipExcludedBounds);
pw.println(" mEdgeWidthLeft=" + mEdgeWidthLeft);
pw.println(" mEdgeWidthRight=" + mEdgeWidthRight);
- pw.println(" mIsNavBarShownTransiently=" + mIsNavBarShownTransiently);
- pw.println(" mPredictionLog=" + String.join(";", mPredictionLog));
+ pw.println(" mLeftInset=" + mLeftInset);
+ pw.println(" mRightInset=" + mRightInset);
+ pw.println(" mMLEnableWidth=" + mMLEnableWidth);
+ pw.println(" mMLModelThreshold=" + mMLModelThreshold);
+ pw.println(" mTouchSlop=" + mTouchSlop);
+ pw.println(" mBottomGestureHeight=" + mBottomGestureHeight);
+ pw.println(" mPredictionLog=" + String.join("\n", mPredictionLog));
+ pw.println(" mGestureLog=" + String.join("\n", mGestureLog));
pw.println(" mEdgeBackPlugin=" + mEdgeBackPlugin);
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index cd1131ba3e79..5dda23e4a47e 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -16,6 +16,7 @@
package com.android.systemui.people;
+import static android.app.Notification.CATEGORY_MISSED_CALL;
import static android.app.Notification.EXTRA_MESSAGES;
import static android.app.people.ConversationStatus.ACTIVITY_ANNIVERSARY;
import static android.app.people.ConversationStatus.ACTIVITY_BIRTHDAY;
@@ -189,7 +190,7 @@ public class PeopleSpaceUtils {
tiles.addAll(recentTiles);
}
- tiles = augmentTilesFromVisibleNotifications(tiles, notificationEntryManager);
+ tiles = augmentTilesFromVisibleNotifications(context, tiles, notificationEntryManager);
return tiles;
}
@@ -357,8 +358,8 @@ public class PeopleSpaceUtils {
&& storedUserId == userId;
}
- static List<PeopleSpaceTile> augmentTilesFromVisibleNotifications(List<PeopleSpaceTile> tiles,
- NotificationEntryManager notificationEntryManager) {
+ static List<PeopleSpaceTile> augmentTilesFromVisibleNotifications(Context context,
+ List<PeopleSpaceTile> tiles, NotificationEntryManager notificationEntryManager) {
if (notificationEntryManager == null) {
Log.w(TAG, "NotificationEntryManager is null");
return tiles;
@@ -374,12 +375,13 @@ public class PeopleSpaceUtils {
}
return tiles
.stream()
- .map(entry -> augmentTileFromVisibleNotifications(entry, visibleNotifications))
+ .map(entry -> augmentTileFromVisibleNotifications(
+ context, entry, visibleNotifications))
.collect(Collectors.toList());
}
- static PeopleSpaceTile augmentTileFromVisibleNotifications(PeopleSpaceTile tile,
- Map<String, NotificationEntry> visibleNotifications) {
+ static PeopleSpaceTile augmentTileFromVisibleNotifications(Context context,
+ PeopleSpaceTile tile, Map<String, NotificationEntry> visibleNotifications) {
String shortcutId = tile.getId();
String packageName = tile.getPackageName();
int userId = UserHandle.getUserHandleForUid(tile.getUid()).getIdentifier();
@@ -389,7 +391,7 @@ public class PeopleSpaceUtils {
return tile;
}
if (DEBUG) Log.d(TAG, "Augmenting tile from visible notifications, key:" + key);
- return augmentTileFromNotification(tile, visibleNotifications.get(key).getSbn());
+ return augmentTileFromNotification(context, tile, visibleNotifications.get(key).getSbn());
}
/**
@@ -408,7 +410,7 @@ public class PeopleSpaceUtils {
}
if (notificationAction == PeopleSpaceUtils.NotificationAction.POSTED) {
if (DEBUG) Log.i(TAG, "Adding notification to storage, appWidgetId: " + appWidgetId);
- storedTile = augmentTileFromNotification(storedTile, sbn);
+ storedTile = augmentTileFromNotification(context, storedTile, sbn);
} else {
if (DEBUG) {
Log.i(TAG, "Removing notification from storage, appWidgetId: " + appWidgetId);
@@ -418,23 +420,40 @@ public class PeopleSpaceUtils {
.setNotificationKey(null)
.setNotificationContent(null)
.setNotificationDataUri(null)
+ .setNotificationCategory(null)
.build();
}
updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId, storedTile);
}
- static PeopleSpaceTile augmentTileFromNotification(PeopleSpaceTile tile,
+ static PeopleSpaceTile augmentTileFromNotification(Context context, PeopleSpaceTile tile,
StatusBarNotification sbn) {
- Notification.MessagingStyle.Message message = getLastMessagingStyleMessage(sbn);
- if (message == null) {
- if (DEBUG) Log.i(TAG, "Notification doesn't have content, skipping.");
+ Notification notification = sbn.getNotification();
+ if (notification == null) {
+ if (DEBUG) Log.d(TAG, "Notification is null");
+ return tile;
+ }
+ boolean isMissedCall = Objects.equals(notification.category, CATEGORY_MISSED_CALL);
+ Notification.MessagingStyle.Message message = getLastMessagingStyleMessage(notification);
+
+ if (!isMissedCall && message == null) {
+ if (DEBUG) Log.d(TAG, "Notification has no content");
return tile;
}
+
+ // If it's a missed call notification and it doesn't include content, use fallback value,
+ // otherwise, use notification content.
+ boolean hasMessageText = message != null && !TextUtils.isEmpty(message.getText());
+ CharSequence content = (isMissedCall && !hasMessageText)
+ ? context.getString(R.string.missed_call) : message.getText();
+ Uri dataUri = message != null ? message.getDataUri() : null;
+
return tile
.toBuilder()
.setNotificationKey(sbn.getKey())
- .setNotificationContent(message.getText())
- .setNotificationDataUri(message.getDataUri())
+ .setNotificationCategory(notification.category)
+ .setNotificationContent(content)
+ .setNotificationDataUri(dataUri)
.build();
}
@@ -462,6 +481,11 @@ public class PeopleSpaceUtils {
* content, then birthdays, then the most recent status, and finally last interaction.
*/
private static RemoteViews getViewForTile(Context context, PeopleSpaceTile tile) {
+ if (Objects.equals(tile.getNotificationCategory(), CATEGORY_MISSED_CALL)) {
+ if (DEBUG) Log.d(TAG, "Create missed call view");
+ return createMissedCallRemoteViews(context, tile);
+ }
+
if (tile.getNotificationKey() != null) {
if (DEBUG) Log.d(TAG, "Create notification view");
return createNotificationRemoteViews(context, tile);
@@ -630,6 +654,16 @@ public class PeopleSpaceUtils {
return views;
}
+ private static RemoteViews createMissedCallRemoteViews(Context context,
+ PeopleSpaceTile tile) {
+ RemoteViews views = new RemoteViews(
+ context.getPackageName(), R.layout.people_space_small_avatar_tile);
+ views.setTextViewText(R.id.status, tile.getNotificationContent());
+ views.setImageViewResource(R.id.status_defined_icon, R.drawable.ic_phone_missed);
+ views.setBoolean(R.id.content_background, "setClipToOutline", true);
+ return views;
+ }
+
private static RemoteViews createNotificationRemoteViews(Context context,
PeopleSpaceTile tile) {
RemoteViews views = new RemoteViews(
@@ -715,8 +749,7 @@ public class PeopleSpaceUtils {
/** Gets the most recent {@link Notification.MessagingStyle.Message} from the notification. */
@VisibleForTesting
public static Notification.MessagingStyle.Message getLastMessagingStyleMessage(
- StatusBarNotification sbn) {
- Notification notification = sbn.getNotification();
+ Notification notification) {
if (notification == null) {
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java
index b188acbf30f3..3df264421d75 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java
@@ -23,6 +23,7 @@ import android.util.Log;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.people.PeopleSpaceActivity;
import com.android.systemui.statusbar.FeatureFlags;
import javax.inject.Inject;
@@ -54,6 +55,12 @@ public class PeopleSpaceWidgetEnabler extends SystemUI {
? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
+ mContext.getPackageManager().setComponentEnabledSetting(
+ new ComponentName(mContext, PeopleSpaceActivity.class),
+ showPeopleSpace
+ ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
} catch (Exception e) {
Log.w(TAG, "Error enabling People Space widget:", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index bee9889eaa4e..9e5c786b9a63 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -29,7 +29,6 @@ import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;
-import android.widget.RemoteViews;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.appwidget.IAppWidgetService;
@@ -124,8 +123,6 @@ public class PeopleSpaceWidgetManager {
*/
public void updateWidgetWithNotificationChanged(StatusBarNotification sbn,
PeopleSpaceUtils.NotificationAction notificationAction) {
- RemoteViews views = new RemoteViews(
- mContext.getPackageName(), R.layout.people_space_small_avatar_tile);
if (DEBUG) Log.d(TAG, "updateWidgetWithNotificationChanged called");
boolean showSingleConversation = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
index c9d1b71bca77..0fa7b59d0e54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
+++ b/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,9 +14,8 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.tv.micdisclosure;
+package com.android.systemui.privacy.television;
-import static android.provider.DeviceConfig.NAMESPACE_PRIVACY;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import android.animation.Animator;
@@ -25,57 +24,56 @@ import android.animation.ObjectAnimator;
import android.annotation.IntDef;
import android.annotation.UiThread;
import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Color;
import android.graphics.PixelFormat;
-import android.provider.DeviceConfig;
-import android.text.TextUtils;
-import android.util.ArraySet;
+import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
import com.android.systemui.R;
-import com.android.systemui.statusbar.tv.TvStatusBar;
+import com.android.systemui.SystemUI;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.privacy.PrivacyChipBuilder;
+import com.android.systemui.privacy.PrivacyItem;
+import com.android.systemui.privacy.PrivacyItemController;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
-import java.util.Set;
+
+import javax.inject.Inject;
/**
- * A component of {@link TvStatusBar} responsible for notifying the user whenever an application is
- * recording audio.
- *
- * @see TvStatusBar
+ * A SystemUI component responsible for notifying the user whenever an application is
+ * recording audio, accessing the camera or accessing the location.
*/
-public class AudioRecordingDisclosureBar implements
- AudioActivityObserver.OnAudioActivityStateChangeListener {
- private static final String TAG = "AudioRecordingDisclosure";
+@SysUISingleton
+public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemController.Callback {
+ private static final String TAG = "TvOngoingPrivacyChip";
static final boolean DEBUG = false;
- // This title is used to test the microphone disclosure indicator in
- // CtsSystemUiHostTestCases:TvMicrophoneCaptureIndicatorTest
+ // This title is used in CameraMicIndicatorsPermissionTest and
+ // RecognitionServiceMicIndicatorTest.
private static final String LAYOUT_PARAMS_TITLE = "MicrophoneCaptureIndicator";
- private static final String ENABLED_FLAG = "mic_disclosure_enabled";
- private static final String EXEMPT_PACKAGES_LIST = "mic_disclosure_exempt_packages";
- private static final String FORCED_PACKAGES_LIST = "mic_disclosure_forced_packages";
-
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"STATE_"}, value = {
- STATE_STOPPED,
STATE_NOT_SHOWN,
STATE_APPEARING,
STATE_SHOWN,
STATE_DISAPPEARING
})
- public @interface State {}
+ public @interface State {
+ }
- private static final int STATE_STOPPED = -1;
private static final int STATE_NOT_SHOWN = 0;
private static final int STATE_APPEARING = 1;
private static final int STATE_SHOWN = 2;
@@ -84,106 +82,89 @@ public class AudioRecordingDisclosureBar implements
private static final int ANIMATION_DURATION_MS = 200;
private final Context mContext;
- private boolean mIsEnabled;
+ private final PrivacyItemController mPrivacyItemController;
private View mIndicatorView;
private boolean mViewAndWindowAdded;
private ObjectAnimator mAnimator;
- @State private int mState = STATE_STOPPED;
+ private boolean mAllIndicatorsFlagEnabled;
+ private boolean mMicCameraIndicatorFlagEnabled;
+ private boolean mLocationIndicatorEnabled;
+ private List<PrivacyItem> mPrivacyItems;
- /**
- * Array of the observers that monitor different aspects of the system, such as AppOps and
- * microphone foreground services
- */
- private AudioActivityObserver[] mAudioActivityObservers;
- /**
- * Set of applications for which we make an exception and do not show the indicator. This gets
- * populated once - in {@link #AudioRecordingDisclosureBar(Context)}.
- */
- private final Set<String> mExemptPackages = new ArraySet<>();
+ private LinearLayout mIconsContainer;
+ private final int mIconSize;
+ private final int mIconMarginStart;
- public AudioRecordingDisclosureBar(Context context) {
+ @State
+ private int mState = STATE_NOT_SHOWN;
+
+ @Inject
+ public TvOngoingPrivacyChip(Context context, PrivacyItemController privacyItemController) {
+ super(context);
+ Log.d(TAG, "Privacy chip running without id");
mContext = context;
+ mPrivacyItemController = privacyItemController;
- // Load configs
- reloadExemptPackages();
+ Resources res = mContext.getResources();
+ mIconMarginStart = Math.round(res.getDimension(R.dimen.privacy_chip_icon_margin));
+ mIconSize = res.getDimensionPixelSize(R.dimen.privacy_chip_icon_size);
- mIsEnabled = DeviceConfig.getBoolean(NAMESPACE_PRIVACY, ENABLED_FLAG, true);
- // Start if enabled
- if (mIsEnabled) {
- start();
- }
+ mAllIndicatorsFlagEnabled = privacyItemController.getAllIndicatorsAvailable();
+ mMicCameraIndicatorFlagEnabled = privacyItemController.getMicCameraAvailable();
+ mLocationIndicatorEnabled = privacyItemController.getLocationAvailable();
- // Set up a config change listener
- DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_PRIVACY, mContext.getMainExecutor(),
- mConfigChangeListener);
+ if (DEBUG) {
+ Log.d(TAG, "allIndicators: " + mAllIndicatorsFlagEnabled);
+ Log.d(TAG, "micCameraIndicators: " + mMicCameraIndicatorFlagEnabled);
+ Log.d(TAG, "locationIndicators: " + mLocationIndicatorEnabled);
+ }
}
- private void reloadExemptPackages() {
- mExemptPackages.clear();
- mExemptPackages.addAll(Arrays.asList(mContext.getResources().getStringArray(
- R.array.audio_recording_disclosure_exempt_apps)));
- mExemptPackages.addAll(
- splitByComma(
- DeviceConfig.getString(NAMESPACE_PRIVACY, EXEMPT_PACKAGES_LIST, null)));
- mExemptPackages.removeAll(
- splitByComma(
- DeviceConfig.getString(NAMESPACE_PRIVACY, FORCED_PACKAGES_LIST, null)));
+ @Override
+ public void start() {
+ mPrivacyItemController.addCallback(this);
}
- @UiThread
- private void start() {
- if (mState != STATE_STOPPED) {
- return;
- }
- mState = STATE_NOT_SHOWN;
-
- if (mAudioActivityObservers == null) {
- mAudioActivityObservers = new AudioActivityObserver[]{
- new RecordAudioAppOpObserver(mContext, this),
- new MicrophoneForegroundServicesObserver(mContext, this),
- };
- }
-
- for (int i = mAudioActivityObservers.length - 1; i >= 0; i--) {
- mAudioActivityObservers[i].start();
- }
+ @Override
+ public void onPrivacyItemsChanged(List<PrivacyItem> privacyItems) {
+ if (DEBUG) Log.d(TAG, "PrivacyItemsChanged");
+ mPrivacyItems = privacyItems;
+ updateUI();
}
- @UiThread
- private void stop() {
- if (mState == STATE_STOPPED) {
- return;
- }
- mState = STATE_STOPPED;
-
- for (int i = mAudioActivityObservers.length - 1; i >= 0; i--) {
- mAudioActivityObservers[i].stop();
- }
-
- // Remove the view if shown.
- if (mState != STATE_NOT_SHOWN) {
- removeIndicatorView();
- }
+ @Override
+ public void onFlagAllChanged(boolean flag) {
+ if (DEBUG) Log.d(TAG, "all indicators enabled: " + flag);
+ mAllIndicatorsFlagEnabled = flag;
}
- @UiThread
@Override
- public void onAudioActivityStateChange(boolean active, String packageName) {
- if (DEBUG) {
- Log.d(TAG,
- "onAudioActivityStateChange, packageName=" + packageName + ", active="
- + active);
- }
+ public void onFlagMicCameraChanged(boolean flag) {
+ if (DEBUG) Log.d(TAG, "mic/camera indicators enabled: " + flag);
+ mMicCameraIndicatorFlagEnabled = flag;
+ }
- if (mExemptPackages.contains(packageName)) {
- if (DEBUG) Log.d(TAG, " - exempt package: ignoring");
- return;
- }
+ @Override
+ public void onFlagLocationChanged(boolean flag) {
+ if (DEBUG) Log.d(TAG, "location indicators enabled: " + flag);
+ mLocationIndicatorEnabled = flag;
+ }
- if (active) {
- showIfNeeded();
+ private void updateUI() {
+ if (DEBUG) Log.d(TAG, mPrivacyItems.size() + " privacy items");
+
+ if ((mMicCameraIndicatorFlagEnabled || mAllIndicatorsFlagEnabled
+ || mLocationIndicatorEnabled) && !mPrivacyItems.isEmpty()) {
+ if (mState == STATE_NOT_SHOWN || mState == STATE_DISAPPEARING) {
+ showIndicator();
+ } else {
+ if (DEBUG) Log.d(TAG, "only updating icons");
+ PrivacyChipBuilder builder = new PrivacyChipBuilder(mContext, mPrivacyItems);
+ setIcons(builder.generateIcons(), mIconsContainer);
+ mIconsContainer.requestLayout();
+ }
} else {
hideIndicatorIfNeeded();
}
@@ -191,12 +172,7 @@ public class AudioRecordingDisclosureBar implements
@UiThread
private void hideIndicatorIfNeeded() {
- // If STOPPED, NOT_SHOWN or DISAPPEARING - nothing else for us to do here.
- if (mState != STATE_SHOWN && mState != STATE_APPEARING) return;
-
- if (hasActiveRecorders()) {
- return;
- }
+ if (mState == STATE_NOT_SHOWN || mState == STATE_DISAPPEARING) return;
if (mViewAndWindowAdded) {
mState = STATE_DISAPPEARING;
@@ -210,23 +186,12 @@ public class AudioRecordingDisclosureBar implements
}
@UiThread
- private void showIfNeeded() {
- // If STOPPED, SHOWN or APPEARING - nothing else for us to do here.
- if (mState != STATE_NOT_SHOWN && mState != STATE_DISAPPEARING) return;
-
- if (DEBUG) Log.d(TAG, "Showing indicator");
-
- final int prevState = mState;
+ private void showIndicator() {
mState = STATE_APPEARING;
- if (prevState == STATE_DISAPPEARING) {
- animateAppearance();
- return;
- }
-
// Inflate the indicator view
mIndicatorView = LayoutInflater.from(mContext).inflate(
- R.layout.tv_audio_recording_indicator, null);
+ R.layout.tv_ongoing_privacy_chip, null);
// 1. Set alpha to 0.
// 2. Wait until the window is shown and the view is laid out.
@@ -239,7 +204,7 @@ public class AudioRecordingDisclosureBar implements
@Override
public void onGlobalLayout() {
// State could have changed to NOT_SHOWN (if all the recorders are
- // already gone) to STOPPED (if the indicator was disabled)
+ // already gone)
if (mState != STATE_APPEARING) return;
mViewAndWindowAdded = true;
@@ -251,22 +216,41 @@ public class AudioRecordingDisclosureBar implements
}
});
- final boolean isLtr = mContext.getResources().getConfiguration().getLayoutDirection()
- == View.LAYOUT_DIRECTION_LTR;
+ mIconsContainer = mIndicatorView.findViewById(R.id.icons_container);
+ PrivacyChipBuilder builder = new PrivacyChipBuilder(mContext, mPrivacyItems);
+ setIcons(builder.generateIcons(), mIconsContainer);
+
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
WRAP_CONTENT,
WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
- layoutParams.gravity = Gravity.TOP | (isLtr ? Gravity.RIGHT : Gravity.LEFT);
+ layoutParams.gravity = Gravity.TOP | Gravity.END;
layoutParams.setTitle(LAYOUT_PARAMS_TITLE);
layoutParams.packageName = mContext.getPackageName();
- final WindowManager windowManager = (WindowManager) mContext.getSystemService(
- Context.WINDOW_SERVICE);
+ final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
windowManager.addView(mIndicatorView, layoutParams);
+
}
+ private void setIcons(List<Drawable> icons, ViewGroup iconsContainer) {
+ iconsContainer.removeAllViews();
+ for (int i = 0; i < icons.size(); i++) {
+ Drawable icon = icons.get(i);
+ icon.mutate().setTint(Color.WHITE);
+ ImageView imageView = new ImageView(mContext);
+ imageView.setImageDrawable(icon);
+ imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
+ mIconsContainer.addView(imageView, mIconSize, mIconSize);
+ if (i != 0) {
+ ViewGroup.MarginLayoutParams layoutParams =
+ (ViewGroup.MarginLayoutParams) imageView.getLayoutParams();
+ layoutParams.setMarginStart(mIconMarginStart);
+ imageView.setLayoutParams(layoutParams);
+ }
+ }
+ }
private void animateAppearance() {
animateAlphaTo(1f);
@@ -333,22 +317,13 @@ public class AudioRecordingDisclosureBar implements
}
}
- private boolean hasActiveRecorders() {
- for (int index = mAudioActivityObservers.length - 1; index >= 0; index--) {
- for (String activePackage : mAudioActivityObservers[index].getActivePackages()) {
- if (mExemptPackages.contains(activePackage)) continue;
- return true;
- }
- }
- return false;
- }
-
private void removeIndicatorView() {
if (DEBUG) Log.d(TAG, "removeIndicatorView");
- final WindowManager windowManager = (WindowManager) mContext.getSystemService(
- Context.WINDOW_SERVICE);
- windowManager.removeView(mIndicatorView);
+ final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
+ if (windowManager != null) {
+ windowManager.removeView(mIndicatorView);
+ }
mIndicatorView = null;
mAnimator = null;
@@ -356,26 +331,4 @@ public class AudioRecordingDisclosureBar implements
mViewAndWindowAdded = false;
}
- private static List<String> splitByComma(String string) {
- return TextUtils.isEmpty(string) ? Collections.emptyList() : Arrays.asList(
- string.split(","));
- }
-
- private final DeviceConfig.OnPropertiesChangedListener mConfigChangeListener =
- new DeviceConfig.OnPropertiesChangedListener() {
- @Override
- public void onPropertiesChanged(DeviceConfig.Properties properties) {
- reloadExemptPackages();
-
- // Check if was enabled/disabled
- if (mIsEnabled != properties.getBoolean(ENABLED_FLAG, true)) {
- mIsEnabled = !mIsEnabled;
- if (mIsEnabled) {
- start();
- } else {
- stop();
- }
- }
- }
- };
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
index 1386ddfa7692..53d9f1c08e6f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
@@ -97,8 +97,8 @@ public class CropView extends View {
float bottom = mBottomCrop + mBottomDelta;
drawShade(canvas, 0, top);
drawShade(canvas, bottom, 1f);
- drawHandle(canvas, top);
- drawHandle(canvas, bottom);
+ drawHandle(canvas, top, /* draw the handle tab down */ false);
+ drawHandle(canvas, bottom, /* draw the handle tab up */ true);
}
@Override
@@ -122,7 +122,7 @@ public class CropView extends View {
} else { // Bottom
mBottomDelta = pixelsToFraction((int) MathUtils.constrain(delta,
topPx + 2 * mCropTouchMargin - bottomPx,
- getMeasuredHeight() - bottomPx));
+ getHeight() - bottomPx));
}
updateListener(event);
invalidate();
@@ -212,21 +212,25 @@ public class CropView extends View {
}
private void drawShade(Canvas canvas, float fracStart, float fracEnd) {
- canvas.drawRect(0, fractionToPixels(fracStart), getMeasuredWidth(),
+ canvas.drawRect(0, fractionToPixels(fracStart), getWidth(),
fractionToPixels(fracEnd), mShadePaint);
}
- private void drawHandle(Canvas canvas, float frac) {
+ private void drawHandle(Canvas canvas, float frac, boolean handleTabUp) {
int y = fractionToPixels(frac);
- canvas.drawLine(0, y, getMeasuredWidth(), y, mHandlePaint);
+ canvas.drawLine(0, y, getWidth(), y, mHandlePaint);
+ float radius = 15 * getResources().getDisplayMetrics().density;
+ float x = getWidth() * .9f;
+ canvas.drawArc(x - radius, y - radius, x + radius, y + radius, handleTabUp ? 180 : 0, 180,
+ true, mHandlePaint);
}
private int fractionToPixels(float frac) {
- return (int) (frac * getMeasuredHeight());
+ return (int) (frac * getHeight());
}
private float pixelsToFraction(int px) {
- return px / (float) getMeasuredHeight();
+ return px / (float) getHeight();
}
private CropBoundary nearestBoundary(MotionEvent event, int topPx, int bottomPx) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index a6433ae94b2b..89efda98a5b6 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -46,6 +46,7 @@ public class LongScreenshotActivity extends Activity {
private final UiEventLogger mUiEventLogger;
private final ScrollCaptureController mScrollCaptureController;
+ private final ScrollCaptureClient.Connection mConnection;
private ImageView mPreview;
private View mSave;
@@ -69,8 +70,10 @@ public class LongScreenshotActivity extends Activity {
Context context) {
mUiEventLogger = uiEventLogger;
- mScrollCaptureController = new ScrollCaptureController(context,
- ScreenshotController.sScrollConnection, mainExecutor, bgExecutor, imageExporter);
+ mScrollCaptureController = new ScrollCaptureController(context, mainExecutor, bgExecutor,
+ imageExporter);
+
+ mConnection = ScreenshotController.takeScrollCaptureConnection();
}
@Override
@@ -98,15 +101,20 @@ public class LongScreenshotActivity extends Activity {
public void onStart() {
super.onStart();
if (mPreview.getDrawable() == null) {
+ if (mConnection == null) {
+ Log.e(TAG, "Failed to get scroll capture connection, bailing out");
+ finishAndRemoveTask();
+ return;
+ }
doCapture();
}
}
- private void disableButtons() {
- mSave.setEnabled(false);
- mCancel.setEnabled(false);
- mEdit.setEnabled(false);
- mShare.setEnabled(false);
+ private void setButtonsEnabled(boolean enabled) {
+ mSave.setEnabled(enabled);
+ mCancel.setEnabled(enabled);
+ mEdit.setEnabled(enabled);
+ mShare.setEnabled(enabled);
}
private void doEdit(Uri uri) {
@@ -115,8 +123,7 @@ public class LongScreenshotActivity extends Activity {
if (!TextUtils.isEmpty(editorPackage)) {
intent.setComponent(ComponentName.unflattenFromString(editorPackage));
}
- intent.setType("image/png");
- intent.setData(uri);
+ intent.setDataAndType(uri, "image/png");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
@@ -127,12 +134,11 @@ public class LongScreenshotActivity extends Activity {
private void doShare(Uri uri) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/png");
- intent.setData(uri);
+ intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_GRANT_READ_URI_PERMISSION);
Intent sharingChooserIntent = Intent.createChooser(intent, null)
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityAsUser(sharingChooserIntent, UserHandle.CURRENT);
}
@@ -140,7 +146,7 @@ public class LongScreenshotActivity extends Activity {
private void onClicked(View v) {
int id = v.getId();
v.setPressed(true);
- disableButtons();
+ setButtonsEnabled(false);
if (id == R.id.save) {
startExport(PendingAction.SAVE);
} else if (id == R.id.cancel) {
@@ -160,10 +166,12 @@ public class LongScreenshotActivity extends Activity {
@Override
public void onError() {
Log.e(TAG, "Error exporting image data.");
+ setButtonsEnabled(true);
}
@Override
public void onExportComplete(Uri outputUri) {
+ setButtonsEnabled(true);
switch (action) {
case EDIT:
doEdit(outputUri);
@@ -181,7 +189,8 @@ public class LongScreenshotActivity extends Activity {
}
private void doCapture() {
- mScrollCaptureController.start(new ScrollCaptureController.ScrollCaptureCallback() {
+ mScrollCaptureController.start(mConnection,
+ new ScrollCaptureController.ScrollCaptureCallback() {
@Override
public void onError() {
Log.e(TAG, "Error!");
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 31c693bdde1f..131fde6b4b56 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -101,7 +101,7 @@ import javax.inject.Inject;
public class ScreenshotController {
private static final String TAG = logTag(ScreenshotController.class);
- public static ScrollCaptureClient.Connection sScrollConnection;
+ private static ScrollCaptureClient.Connection sScrollConnection;
/**
* POD used in the AsyncTask which saves an image in the background.
@@ -222,6 +222,12 @@ public class ScreenshotController {
| ActivityInfo.CONFIG_SCREEN_LAYOUT
| ActivityInfo.CONFIG_ASSETS_PATHS);
+ public static @Nullable ScrollCaptureClient.Connection takeScrollCaptureConnection() {
+ ScrollCaptureClient.Connection connection = sScrollConnection;
+ sScrollConnection = null;
+ return connection;
+ }
+
@Inject
ScreenshotController(
Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index 863116a22ee4..4a3ffa45ab81 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -53,7 +53,6 @@ public class ScrollCaptureController {
public static final int MAX_HEIGHT = 12000;
- private final Connection mConnection;
private final Context mContext;
private final Executor mUiExecutor;
@@ -65,10 +64,9 @@ public class ScrollCaptureController {
private UUID mRequestId;
private ScrollCaptureCallback mCaptureCallback;
- public ScrollCaptureController(Context context, Connection connection, Executor uiExecutor,
- Executor bgExecutor, ImageExporter exporter) {
+ public ScrollCaptureController(Context context, Executor uiExecutor, Executor bgExecutor,
+ ImageExporter exporter) {
mContext = context;
- mConnection = connection;
mUiExecutor = uiExecutor;
mBgExecutor = bgExecutor;
mImageExporter = exporter;
@@ -78,16 +76,17 @@ public class ScrollCaptureController {
/**
* Run scroll capture!
*
+ * @param connection connection to the remote window to be used
* @param callback request callback to report back to the service
*/
- public void start(ScrollCaptureCallback callback) {
+ public void start(Connection connection, ScrollCaptureCallback callback) {
mCaptureTime = ZonedDateTime.now();
mRequestId = UUID.randomUUID();
mCaptureCallback = callback;
float maxPages = Settings.Secure.getFloat(mContext.getContentResolver(),
SETTING_KEY_MAX_PAGES, MAX_PAGES_DEFAULT);
- mConnection.start(this::startCapture, maxPages);
+ connection.start(this::startCapture, maxPages);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java
index a6aec3b7b1b7..0b40e225fb2b 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java
@@ -17,8 +17,6 @@
package com.android.systemui.settings.brightness;
import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -29,10 +27,8 @@ import android.widget.SeekBar;
import androidx.annotation.Nullable;
import com.android.settingslib.RestrictedLockUtils;
-import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
-import com.android.systemui.util.RoundedCornerProgressDrawable;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
@@ -274,9 +270,6 @@ public class BrightnessSlider
private BrightnessSlider fromTree(ViewGroup root, boolean useMirror) {
BrightnessSliderView v = root.requireViewById(R.id.brightness_slider);
- // TODO(175026098) Workaround. Remove when b/175026098 is fixed
- applyTheme(v);
-
return new BrightnessSlider(root, v, useMirror);
}
@@ -286,32 +279,5 @@ public class BrightnessSlider
? R.layout.quick_settings_brightness_dialog_thick
: R.layout.quick_settings_brightness_dialog;
}
-
- private LayerDrawable findProgressClippableDrawable(BrightnessSliderView v) {
- SeekBar b = v.requireViewById(R.id.slider);
- if (b.getProgressDrawable() instanceof LayerDrawable) {
- Drawable progress = ((LayerDrawable) b.getProgressDrawable())
- .findDrawableByLayerId(com.android.internal.R.id.progress);
- if (progress instanceof RoundedCornerProgressDrawable) {
- Drawable inner = ((RoundedCornerProgressDrawable) progress).getDrawable();
- if (inner instanceof LayerDrawable) {
- return (LayerDrawable) inner;
- }
- }
- }
- return null;
- }
-
- private void applyTheme(BrightnessSliderView v) {
- LayerDrawable layer = findProgressClippableDrawable(v);
- if (layer != null) {
- layer.findDrawableByLayerId(R.id.slider_foreground).setTintList(
- Utils.getColorAttr(v.getContext(),
- com.android.internal.R.attr.colorControlActivated));
- layer.findDrawableByLayerId(R.id.slider_icon).setTintList(
- Utils.getColorAttr(v.getContext(),
- com.android.internal.R.attr.colorBackground));
- }
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index 862c27907e0f..cf77e290ebe3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -82,4 +82,8 @@ public class FeatureFlags {
public boolean isMonetEnabled() {
return mFlagReader.isEnabled(R.bool.flag_monet);
}
+
+ public boolean isNavigationBarOverlayEnabled() {
+ return mFlagReader.isEnabled(R.bool.flag_navigation_bar_overlay);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java b/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
index f2adaf042b2f..9ed9659c7ab8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
@@ -207,7 +207,7 @@ public class GestureRecorder {
sb.append(g.toJson());
count++;
}
- mLastSaveLen = count;
+ mLastSaveLen += count;
sb.append("]");
return sb.toString();
}
@@ -249,7 +249,9 @@ public class GestureRecorder {
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
save();
if (mLastSaveLen >= 0) {
- pw.println(String.valueOf(mLastSaveLen) + " gestures written to " + mLogfile);
+ pw.println(String.valueOf(mLastSaveLen)
+ + " gestures since last dump written to " + mLogfile);
+ mLastSaveLen = 0;
} else {
pw.println("error writing gestures");
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 7c3b791aed09..c8c0755344a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -548,8 +548,6 @@ public class NotificationEntryManager implements
try {
mStatusBarService.onNotificationClear(
notification.getPackageName(),
- notification.getTag(),
- notification.getId(),
notification.getUser().getIdentifier(),
notification.getKey(),
dismissedByUserStats.dismissalSurface,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index d617dff372da..6b96ee4fc8e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -254,8 +254,6 @@ public class NotifCollection implements Dumpable {
try {
mStatusBarService.onNotificationClear(
entry.getSbn().getPackageName(),
- entry.getSbn().getTag(),
- entry.getSbn().getId(),
entry.getSbn().getUser().getIdentifier(),
entry.getSbn().getKey(),
stats.dismissalSurface,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 5fff8c83048f..0ef4c4d3b788 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -36,12 +36,12 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
-import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.CachingIconView;
import com.android.settingslib.Utils;
+import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.notification.TransformState;
@@ -61,6 +61,7 @@ public abstract class NotificationViewWrapper implements TransformableView {
private int mLightTextColor;
private int mDarkTextColor;
private int mDefaultTextColor;
+ private boolean mAdjustTheme;
public static NotificationViewWrapper wrap(Context ctx, View v, ExpandableNotificationRow row) {
if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
@@ -97,6 +98,8 @@ public abstract class NotificationViewWrapper implements TransformableView {
mView = view;
mRow = row;
onReinflated();
+ mAdjustTheme = ctx.getResources().getBoolean(
+ R.bool.config_adjustThemeOnNotificationCustomViews);
}
/**
@@ -124,12 +127,12 @@ public abstract class NotificationViewWrapper implements TransformableView {
mLightTextColor = mView.getContext().getColor(
com.android.internal.R.color.notification_primary_text_color_light);
mDarkTextColor = mView.getContext().getColor(
- R.color.notification_primary_text_color_dark);
+ com.android.internal.R.color.notification_primary_text_color_dark);
Context themedContext = new ContextThemeWrapper(mView.getContext(),
- R.style.Theme_DeviceDefault_DayNight);
- mDefaultTextColor = Utils.getColorAttr(themedContext, R.attr.textColorPrimary)
- .getDefaultColor();
+ com.android.internal.R.style.Theme_DeviceDefault_DayNight);
+ mDefaultTextColor = Utils.getColorAttr(themedContext,
+ com.android.internal.R.attr.textColorPrimary).getDefaultColor();
}
protected boolean needsInversion(int defaultBackgroundColor, View view) {
@@ -208,7 +211,7 @@ public abstract class NotificationViewWrapper implements TransformableView {
}
protected void ensureThemeOnChildren() {
- if (mView == null) {
+ if (!mAdjustTheme || mView == null) {
return;
}
@@ -219,26 +222,20 @@ public abstract class NotificationViewWrapper implements TransformableView {
}
// Now let's check if there's unprotected text somewhere, and apply the theme if we find it.
- if (!(mView instanceof ViewGroup)) {
- return;
- }
- processChildrenTextColor((ViewGroup) mView);
+ processTextColorRecursive(mView);
}
- private void processChildrenTextColor(ViewGroup viewGroup) {
- if (viewGroup == null) {
- return;
- }
-
- for (int i = 0; i < viewGroup.getChildCount(); i++) {
- View child = viewGroup.getChildAt(i);
- if (child instanceof TextView) {
- int foreground = ((TextView) child).getCurrentTextColor();
- if (foreground == mLightTextColor || foreground == mDarkTextColor) {
- ((TextView) child).setTextColor(mDefaultTextColor);
- }
- } else if (child instanceof ViewGroup) {
- processChildrenTextColor((ViewGroup) child);
+ private void processTextColorRecursive(View view) {
+ if (view instanceof TextView) {
+ TextView textView = (TextView) view;
+ int foreground = textView.getCurrentTextColor();
+ if (foreground == mLightTextColor || foreground == mDarkTextColor) {
+ textView.setTextColor(mDefaultTextColor);
+ }
+ } else if (view instanceof ViewGroup) {
+ ViewGroup viewGroup = (ViewGroup) view;
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
+ processTextColorRecursive(viewGroup.getChildAt(i));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 2ce403764c7d..d6380199e844 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -89,7 +89,8 @@ public class KeyguardClockPositionAlgorithm {
private int mNotificationStackHeight;
/**
- * Minimum top margin to avoid overlap with status bar.
+ * Minimum top margin to avoid overlap with status bar, lock icon, or multi-user switcher
+ * avatar.
*/
private int mMinTopMargin;
@@ -186,15 +187,15 @@ public class KeyguardClockPositionAlgorithm {
/**
* Sets up algorithm values.
*/
- public void setup(int statusBarMinHeight, int maxShadeBottom, int notificationStackHeight,
- float panelExpansion, int parentHeight, int keyguardStatusHeight,
- int userSwitchHeight, int clockPreferredY, int userSwitchPreferredY,
- boolean hasCustomClock, boolean hasVisibleNotifs, float dark, float emptyDragAmount,
- boolean bypassEnabled, int unlockedStackScrollerPadding, boolean showLockIcon,
- float qsExpansion, int cutoutTopInset) {
- mMinTopMargin = statusBarMinHeight + (showLockIcon
- ? mContainerTopPaddingWithLockIcon : mContainerTopPaddingWithoutLockIcon)
- + userSwitchHeight;
+ public void setup(int keyguardStatusBarHeaderHeight, int maxShadeBottom,
+ int notificationStackHeight, float panelExpansion, int parentHeight,
+ int keyguardStatusHeight, int userSwitchHeight, int clockPreferredY,
+ int userSwitchPreferredY, boolean hasCustomClock, boolean hasVisibleNotifs, float dark,
+ float emptyDragAmount, boolean bypassEnabled, int unlockedStackScrollerPadding,
+ boolean showLockIcon, float qsExpansion, int cutoutTopInset) {
+ mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(showLockIcon
+ ? mContainerTopPaddingWithLockIcon : mContainerTopPaddingWithoutLockIcon,
+ userSwitchHeight);
mMaxShadeBottom = maxShadeBottom;
mNotificationStackHeight = notificationStackHeight;
mPanelExpansion = panelExpansion;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 6940050f754b..093f57adb21a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -287,21 +287,6 @@ public class NotificationPanelViewController extends PanelViewController {
}
};
- final KeyguardUserSwitcherController.KeyguardUserSwitcherListener
- mKeyguardUserSwitcherListener =
- new KeyguardUserSwitcherController.KeyguardUserSwitcherListener() {
- @Override
- public void onKeyguardUserSwitcherChanged(boolean open) {
- if (mKeyguardUserSwitcherController == null) {
- updateUserSwitcherVisibility(false);
- } else if (!mKeyguardUserSwitcherController.isSimpleUserSwitcher()) {
- updateUserSwitcherVisibility(open
- && mKeyguardStateController.isShowing()
- && !mKeyguardStateController.isKeyguardFadingAway());
- }
- }
- };
-
private final LayoutInflater mLayoutInflater;
private final PowerManager mPowerManager;
private final AccessibilityManager mAccessibilityManager;
@@ -329,7 +314,6 @@ public class NotificationPanelViewController extends PanelViewController {
private KeyguardAffordanceHelper mAffordanceHelper;
private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
- private boolean mKeyguardUserSwitcherIsShowing;
private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
private KeyguardStatusBarView mKeyguardStatusBar;
private ViewGroup mBigClockContainer;
@@ -374,6 +358,7 @@ public class NotificationPanelViewController extends PanelViewController {
private ValueAnimator mQsExpansionAnimator;
private FlingAnimationUtils mFlingAnimationUtils;
private int mStatusBarMinHeight;
+ private int mStatusBarHeaderHeightKeyguard;
private int mNotificationsHeaderCollideDistance;
private float mEmptyDragAmount;
private float mDownX;
@@ -772,6 +757,8 @@ public class NotificationPanelViewController extends PanelViewController {
.setMaxLengthSeconds(0.4f).build();
mStatusBarMinHeight = mResources.getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
+ mStatusBarHeaderHeightKeyguard = mResources.getDimensionPixelSize(
+ R.dimen.status_bar_header_height_keyguard);
mQsPeekHeight = mResources.getDimensionPixelSize(R.dimen.qs_peek_height);
mNotificationsHeaderCollideDistance = mResources.getDimensionPixelSize(
R.dimen.header_notifications_collide_distance);
@@ -808,7 +795,6 @@ public class NotificationPanelViewController extends PanelViewController {
// Try to close the switcher so that callbacks are triggered if necessary.
// Otherwise, NPV can get into a state where some of the views are still hidden
mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple(false);
- mKeyguardUserSwitcherController.removeCallback();
}
mKeyguardQsUserSwitchController = null;
@@ -828,7 +814,6 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardUserSwitcherComponentFactory.build(keyguardUserSwitcherView);
mKeyguardUserSwitcherController =
userSwitcherComponent.getKeyguardUserSwitcherController();
- mKeyguardUserSwitcherController.setCallback(mKeyguardUserSwitcherListener);
mKeyguardUserSwitcherController.init();
mKeyguardStatusBar.setKeyguardUserSwitcherEnabled(true);
} else {
@@ -1069,7 +1054,7 @@ public class NotificationPanelViewController extends PanelViewController {
int totalHeight = mView.getHeight();
int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
int clockPreferredY = mKeyguardStatusViewController.getClockPreferredY(totalHeight);
- int userSwitcherPreferredY = mStatusBarMinHeight;
+ int userSwitcherPreferredY = mStatusBarHeaderHeightKeyguard;
boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
final boolean hasVisibleNotifications = mNotificationStackScrollLayoutController
.getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia();
@@ -1078,7 +1063,8 @@ public class NotificationPanelViewController extends PanelViewController {
? mKeyguardQsUserSwitchController.getUserIconHeight()
: (mKeyguardUserSwitcherController != null
? mKeyguardUserSwitcherController.getUserIconHeight() : 0);
- mClockPositionAlgorithm.setup(mStatusBarMinHeight, totalHeight - bottomPadding,
+ mClockPositionAlgorithm.setup(mStatusBarHeaderHeightKeyguard,
+ totalHeight - bottomPadding,
mNotificationStackScrollLayoutController.getIntrinsicContentHeight(),
getExpandedFraction(),
totalHeight,
@@ -3523,34 +3509,6 @@ public class NotificationPanelViewController extends PanelViewController {
return false;
}
- private void updateUserSwitcherVisibility(boolean open) {
- // Do not update if previously called with the same state.
- if (mKeyguardUserSwitcherIsShowing == open) {
- return;
- }
- mKeyguardUserSwitcherIsShowing = open;
-
- if (open) {
- animateKeyguardStatusBarOut();
- mKeyguardStatusViewController.setKeyguardStatusViewVisibility(
- mBarState,
- true /* keyguardFadingAway */,
- true /* goingToFullShade */,
- mBarState);
- setKeyguardBottomAreaVisibility(mBarState, true);
- mNotificationContainerParent.setVisibility(View.GONE);
- } else {
- animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- mKeyguardStatusViewController.setKeyguardStatusViewVisibility(
- StatusBarState.KEYGUARD,
- false,
- false,
- StatusBarState.SHADE_LOCKED);
- setKeyguardBottomAreaVisibility(mBarState, false);
- mNotificationContainerParent.setVisibility(View.VISIBLE);
- }
- }
-
private void updateDisabledUdfpsController() {
final boolean udfpsEnrolled = mAuthController.getUdfpsRegion() != null
&& mAuthController.isUdfpsEnrolled(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 041a97e1d404..b25fced6a212 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -78,6 +78,7 @@ import android.media.AudioAttributes;
import android.metrics.LogMaker;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -276,7 +277,8 @@ public class StatusBar extends SystemUI implements DemoMode,
public static final boolean DEBUG = false;
public static final boolean SPEW = false;
public static final boolean DUMPTRUCK = true; // extra dumpsys info
- public static final boolean DEBUG_GESTURES = false;
+ public static final boolean DEBUG_GESTURES = Build.IS_DEBUGGABLE; // TODO(b/178277858)
+ public static final boolean DEBUG_GESTURES_VERBOSE = true;
public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false;
public static final boolean DEBUG_CAMERA_LIFT = false;
@@ -456,9 +458,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private final DisplayMetrics mDisplayMetrics;
// XXX: gesture research
- private final GestureRecorder mGestureRec = DEBUG_GESTURES
- ? new GestureRecorder("/sdcard/statusbar_gestures.dat")
- : null;
+ private GestureRecorder mGestureRec = null;
private final ScreenPinningRequest mScreenPinningRequest;
@@ -856,6 +856,10 @@ public class StatusBar extends SystemUI implements DemoMode,
mActivityIntentHelper = new ActivityIntentHelper(mContext);
DateTimeView.setReceiverHandler(timeTickHandler);
+
+ if (DEBUG_GESTURES) {
+ mGestureRec = new GestureRecorder(mContext.getCacheDir() + "/statusbar_gestures.dat");
+ }
}
@Override
@@ -2267,7 +2271,7 @@ public class StatusBar extends SystemUI implements DemoMode,
public boolean interceptTouchEvent(MotionEvent event) {
if (DEBUG_GESTURES) {
- if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
+ if (DEBUG_GESTURES_VERBOSE || event.getActionMasked() != MotionEvent.ACTION_MOVE) {
EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH,
event.getActionMasked(), (int) event.getX(), (int) event.getY(),
mDisabled1, mDisabled2);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index b76e451cb681..8845a05cf6f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -19,9 +19,13 @@ package com.android.systemui.statusbar.policy;
import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA;
import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.database.DataSetObserver;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.UserHandle;
@@ -50,7 +54,6 @@ import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.ViewController;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import javax.inject.Inject;
@@ -73,9 +76,10 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS
private final KeyguardUserAdapter mAdapter;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private WeakReference<KeyguardUserSwitcherListener> mKeyguardUserSwitcherCallback;
protected final SysuiStatusBarStateController mStatusBarStateController;
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
+ private ObjectAnimator mBgAnimator;
+ private final KeyguardUserSwitcherScrim mBackground;
// Child views of KeyguardUserSwitcherView
private KeyguardUserSwitcherListView mListView;
@@ -171,6 +175,7 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS
mUserSwitcherController, this);
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView,
keyguardStateController, dozeParameters);
+ mBackground = new KeyguardUserSwitcherScrim(context);
}
@Override
@@ -204,6 +209,9 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS
mKeyguardUpdateMonitor.registerCallback(mInfoCallback);
mStatusBarStateController.addCallback(mStatusBarStateListener);
mScreenLifecycle.addObserver(mScreenObserver);
+ mView.addOnLayoutChangeListener(mBackground);
+ mView.setBackground(mBackground);
+ mBackground.setAlpha(0);
}
@Override
@@ -217,6 +225,9 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS
mKeyguardUpdateMonitor.removeCallback(mInfoCallback);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
mScreenLifecycle.removeObserver(mScreenObserver);
+ mView.removeOnLayoutChangeListener(mBackground);
+ mView.setBackground(null);
+ mBackground.setAlpha(0);
}
/**
@@ -338,6 +349,13 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS
animate);
PropertyAnimator.setProperty(mListView, AnimatableProperty.TRANSLATION_X, -Math.abs(x),
ANIMATION_PROPERTIES, animate);
+
+ Rect r = new Rect();
+ mListView.getDrawingRect(r);
+ mView.offsetDescendantRectToMyCoords(mListView, r);
+ mBackground.setGradientCenter(
+ (int) (mListView.getTranslationX() + r.left + r.width() / 2),
+ (int) (mListView.getTranslationY() + r.top + r.height() / 2));
}
/**
@@ -372,49 +390,52 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS
}
/**
- * Remove the callback if it exists.
- */
- public void removeCallback() {
- if (DEBUG) Log.d(TAG, "removeCallback");
- mKeyguardUserSwitcherCallback = null;
- }
-
- /**
- * Register to receive notifications about keyguard user switcher state
- * (see {@link KeyguardUserSwitcherListener}.
- *
- * Only one callback can be used at a time.
- *
- * @param callback The callback to register
- */
- public void setCallback(KeyguardUserSwitcherListener callback) {
- if (DEBUG) Log.d(TAG, "setCallback");
- mKeyguardUserSwitcherCallback = new WeakReference<>(callback);
- }
-
- /**
- * If user switcher state changes, notifies all {@link KeyguardUserSwitcherListener}.
- * Switcher state is updatd before animations finish.
+ * NOTE: switcher state is updated before animations finish.
*
* @param animate true to animate transition. The user switcher state (i.e.
* {@link #isUserSwitcherOpen()}) is updated before animation is finished.
*/
private void setUserSwitcherOpened(boolean open, boolean animate) {
- boolean wasOpen = mUserSwitcherOpen;
if (DEBUG) {
- Log.d(TAG, String.format("setUserSwitcherOpened: %b -> %b (animate=%b)", wasOpen,
- open, animate));
+ Log.d(TAG,
+ String.format("setUserSwitcherOpened: %b -> %b (animate=%b)",
+ mUserSwitcherOpen, open, animate));
}
mUserSwitcherOpen = open;
- if (mUserSwitcherOpen != wasOpen) {
- notifyUserSwitcherStateChanged();
- }
updateVisibilities(animate);
}
private void updateVisibilities(boolean animate) {
if (DEBUG) Log.d(TAG, String.format("updateVisibilities: animate=%b", animate));
mEndGuestButton.animate().cancel();
+ if (mBgAnimator != null) {
+ mBgAnimator.cancel();
+ }
+
+ if (mUserSwitcherOpen) {
+ mBgAnimator = ObjectAnimator.ofInt(mBackground, "alpha", 0, 255);
+ mBgAnimator.setDuration(400);
+ mBgAnimator.setInterpolator(Interpolators.ALPHA_IN);
+ mBgAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBgAnimator = null;
+ }
+ });
+ mBgAnimator.start();
+ } else {
+ mBgAnimator = ObjectAnimator.ofInt(mBackground, "alpha", 255, 0);
+ mBgAnimator.setDuration(400);
+ mBgAnimator.setInterpolator(Interpolators.ALPHA_OUT);
+ mBgAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBgAnimator = null;
+ }
+ });
+ mBgAnimator.start();
+ }
+
if (mUserSwitcherOpen && mCurrentUserIsGuest) {
// Show the "End guest session" button
mEndGuestButton.setVisibility(View.VISIBLE);
@@ -459,34 +480,6 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS
return mUserSwitcherOpen;
}
- private void notifyUserSwitcherStateChanged() {
- if (DEBUG) {
- Log.d(TAG, String.format("notifyUserSwitcherStateChanged: mUserSwitcherOpen=%b",
- mUserSwitcherOpen));
- }
- if (mKeyguardUserSwitcherCallback != null) {
- KeyguardUserSwitcherListener cb = mKeyguardUserSwitcherCallback.get();
- if (cb != null) {
- cb.onKeyguardUserSwitcherChanged(mUserSwitcherOpen);
- }
- }
- }
-
- /**
- * Callback for keyguard user switcher state information
- */
- public interface KeyguardUserSwitcherListener {
-
- /**
- * Called when the keyguard enters or leaves user switcher mode. This will be called
- * before the animations are finished.
- *
- * @param open if true, keyguard is showing the user switcher or transitioning from/to user
- * switcher mode.
- */
- void onKeyguardUserSwitcherChanged(boolean open);
- }
-
static class KeyguardUserAdapter extends
UserSwitcherController.BaseUserAdapter implements View.OnClickListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
index 49f5bcdd5a44..1d9d33d2aab1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
@@ -26,7 +26,6 @@ import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
-import android.util.LayoutDirection;
import android.view.View;
import com.android.systemui.R;
@@ -38,13 +37,14 @@ public class KeyguardUserSwitcherScrim extends Drawable
implements View.OnLayoutChangeListener {
private static final float OUTER_EXTENT = 2.5f;
- private static final float INNER_EXTENT = 0.75f;
+ private static final float INNER_EXTENT = 0.25f;
private int mDarkColor;
- private int mTop;
private int mAlpha = 255;
private Paint mRadialGradientPaint = new Paint();
- private int mLayoutWidth;
+ private int mCircleX;
+ private int mCircleY;
+ private int mSize;
public KeyguardUserSwitcherScrim(Context context) {
mDarkColor = context.getColor(
@@ -53,14 +53,11 @@ public class KeyguardUserSwitcherScrim extends Drawable
@Override
public void draw(Canvas canvas) {
- boolean isLtr = getLayoutDirection() == LayoutDirection.LTR;
+ if (mAlpha == 0) {
+ return;
+ }
Rect bounds = getBounds();
- float width = bounds.width() * OUTER_EXTENT;
- float height = (mTop + bounds.height()) * OUTER_EXTENT;
- canvas.translate(0, -mTop);
- canvas.scale(1, height / width);
- canvas.drawRect(isLtr ? bounds.right - width : 0, 0,
- isLtr ? bounds.right : bounds.left + width, width, mRadialGradientPaint);
+ canvas.drawRect(bounds.left, bounds.top, bounds.right, bounds.bottom, mRadialGradientPaint);
}
@Override
@@ -88,24 +85,36 @@ public class KeyguardUserSwitcherScrim extends Drawable
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
if (left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom) {
- mLayoutWidth = right - left;
- mTop = top;
+ int width = right - left;
+ int height = bottom - top;
+ mSize = Math.max(width, height);
updatePaint();
}
}
private void updatePaint() {
- if (mLayoutWidth == 0) {
+ if (mSize == 0) {
return;
}
- float radius = mLayoutWidth * OUTER_EXTENT;
- boolean isLtr = getLayoutDirection() == LayoutDirection.LTR;
+ float outerRadius = mSize * OUTER_EXTENT;
mRadialGradientPaint.setShader(
- new RadialGradient(isLtr ? mLayoutWidth : 0, 0, radius,
+ new RadialGradient(mCircleX, mCircleY, outerRadius,
new int[] { Color.argb(
(int) (Color.alpha(mDarkColor) * mAlpha / 255f), 0, 0, 0),
Color.TRANSPARENT },
- new float[] { Math.max(0f, mLayoutWidth * INNER_EXTENT / radius), 1f },
+ new float[] { Math.max(0f, INNER_EXTENT / OUTER_EXTENT), 1f },
Shader.TileMode.CLAMP));
}
+
+ /**
+ * Sets the center of the radial gradient used as a background
+ *
+ * @param x
+ * @param y
+ */
+ public void setGradientCenter(int x, int y) {
+ mCircleX = x;
+ mCircleY = y;
+ updatePaint();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index bdf2b0c24ba5..37a763b740e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -22,12 +22,10 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.tv.micdisclosure.AudioRecordingDisclosureBar;
import javax.inject.Inject;
@@ -36,11 +34,6 @@ import dagger.Lazy;
/**
* Status bar implementation for "large screen" products that mostly present no on-screen nav.
* Serves as a collection of UI components, rather than showing its own UI.
- * The following is the list of elements that constitute the TV-specific status bar:
- * <ul>
- * <li> {@link AudioRecordingDisclosureBar} - shown whenever applications are conducting audio
- * recording, discloses the responsible applications </li>
- * </ul>
*/
@SysUISingleton
public class TvStatusBar extends SystemUI implements CommandQueue.Callbacks {
@@ -66,11 +59,6 @@ public class TvStatusBar extends SystemUI implements CommandQueue.Callbacks {
} catch (RemoteException ex) {
// If the system process isn't there we're doomed anyway.
}
-
- if (mContext.getResources().getBoolean(R.bool.audio_recording_disclosure_enabled)) {
- // Creating AudioRecordingDisclosureBar and just letting it run
- new AudioRecordingDisclosureBar(mContext);
- }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java
deleted file mode 100644
index bbab6253a4d1..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java
+++ /dev/null
@@ -1,48 +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.systemui.statusbar.tv.micdisclosure;
-
-import android.content.Context;
-
-import java.util.Set;
-
-/**
- * A base class for implementing observers for different kinds of activities related to audio
- * recording. These observers are to be initialized by {@link AudioRecordingDisclosureBar} and to
- * report back to it.
- */
-abstract class AudioActivityObserver {
-
- interface OnAudioActivityStateChangeListener {
- void onAudioActivityStateChange(boolean active, String packageName);
- }
-
- final Context mContext;
-
- final OnAudioActivityStateChangeListener mListener;
-
- AudioActivityObserver(Context context, OnAudioActivityStateChangeListener listener) {
- mContext = context;
- mListener = listener;
- }
-
- abstract void start();
-
- abstract void stop();
-
- abstract Set<String> getActivePackages();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java
deleted file mode 100644
index 8caf95fb48f5..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java
+++ /dev/null
@@ -1,200 +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.systemui.statusbar.tv.micdisclosure;
-
-import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
-
-import static com.android.systemui.statusbar.tv.micdisclosure.AudioRecordingDisclosureBar.DEBUG;
-
-import android.annotation.UiThread;
-import android.app.ActivityManager;
-import android.app.IActivityManager;
-import android.app.IProcessObserver;
-import android.content.Context;
-import android.os.RemoteException;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * The purpose of these class is to detect packages that are running foreground services of type
- * 'microphone' and to report back to {@link AudioRecordingDisclosureBar}.
- */
-class MicrophoneForegroundServicesObserver extends AudioActivityObserver {
- private static final String TAG = "MicrophoneForegroundServicesObserver";
-
- private IActivityManager mActivityManager;
- /**
- * A dictionary that maps PIDs to the package names. We only keep track of the PIDs that are
- * "active" (those that are running FGS with FOREGROUND_SERVICE_TYPE_MICROPHONE flag).
- */
- private final SparseArray<String[]> mPidToPackages = new SparseArray<>();
- /**
- * A dictionary that maps "active" packages to the number of the "active" processes associated
- * with those packages. We really only need this in case when one application is running in
- * multiple processes, so that we don't lose track of the package when one of its "active"
- * processes ceases, while others remain "active".
- */
- private final Map<String, Integer> mPackageToProcessCount = new ArrayMap<>();
-
- MicrophoneForegroundServicesObserver(Context context,
- OnAudioActivityStateChangeListener listener) {
- super(context, listener);
- }
-
- @Override
- void start() {
- mActivityManager = ActivityManager.getService();
- try {
- mActivityManager.registerProcessObserver(mProcessObserver);
- } catch (RemoteException e) {
- Log.e(TAG, "Couldn't register process observer", e);
- }
- }
-
- @Override
- void stop() {
- try {
- mActivityManager.unregisterProcessObserver(mProcessObserver);
- } catch (RemoteException e) {
- Log.e(TAG, "Couldn't unregister process observer", e);
- }
- mActivityManager = null;
- mPackageToProcessCount.clear();
- }
-
- @Override
- Set<String> getActivePackages() {
- return mPackageToProcessCount.keySet();
- }
-
- @UiThread
- private void onProcessForegroundServicesChanged(int pid, boolean hasMicFgs) {
- final String[] changedPackages;
- if (hasMicFgs) {
- if (mPidToPackages.contains(pid)) {
- // We are already tracking this pid - ignore.
- changedPackages = null;
- } else {
- changedPackages = getPackageNames(pid);
- mPidToPackages.append(pid, changedPackages);
- }
- } else {
- changedPackages = mPidToPackages.removeReturnOld(pid);
- }
-
- if (changedPackages == null) {
- return;
- }
-
- for (int index = changedPackages.length - 1; index >= 0; index--) {
- final String packageName = changedPackages[index];
- int processCount = mPackageToProcessCount.getOrDefault(packageName, 0);
- final boolean shouldNotify;
- if (hasMicFgs) {
- processCount++;
- shouldNotify = processCount == 1;
- } else {
- processCount--;
- shouldNotify = processCount == 0;
- }
- if (processCount > 0) {
- mPackageToProcessCount.put(packageName, processCount);
- } else {
- mPackageToProcessCount.remove(packageName);
- }
- if (shouldNotify) notifyPackageStateChanged(packageName, hasMicFgs);
- }
- }
-
- @UiThread
- private void onProcessDied(int pid) {
- final String[] packages = mPidToPackages.removeReturnOld(pid);
- if (packages == null) {
- // This PID was not active - ignore.
- return;
- }
-
- for (int index = packages.length - 1; index >= 0; index--) {
- final String packageName = packages[index];
- int processCount = mPackageToProcessCount.getOrDefault(packageName, 0);
- if (processCount <= 0) {
- Log.e(TAG, "Bookkeeping error, process count for " + packageName + " is "
- + processCount);
- continue;
- }
- processCount--;
- if (processCount > 0) {
- mPackageToProcessCount.put(packageName, processCount);
- } else {
- mPackageToProcessCount.remove(packageName);
- notifyPackageStateChanged(packageName, false);
- }
- }
- }
-
- @UiThread
- private void notifyPackageStateChanged(String packageName, boolean active) {
- if (DEBUG) {
- Log.d(TAG, (active ? "New microphone fgs detected" : "Microphone fgs is gone")
- + ", package=" + packageName);
- }
-
- mListener.onAudioActivityStateChange(active, packageName);
- }
-
- @UiThread
- private String[] getPackageNames(int pid) {
- final List<ActivityManager.RunningAppProcessInfo> runningApps;
- try {
- runningApps = mActivityManager.getRunningAppProcesses();
- } catch (RemoteException e) {
- Log.d(TAG, "Couldn't get package name for pid=" + pid);
- return null;
- }
- if (runningApps == null) {
- Log.wtf(TAG, "No running apps reported");
- }
- for (ActivityManager.RunningAppProcessInfo app : runningApps) {
- if (app.pid == pid) {
- return app.pkgList;
- }
- }
- return null;
- }
-
- private final IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
- @Override
- public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {}
-
- @Override
- public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {
- mContext.getMainExecutor().execute(() -> onProcessForegroundServicesChanged(pid,
- (serviceTypes & FOREGROUND_SERVICE_TYPE_MICROPHONE) != 0));
- }
-
- @Override
- public void onProcessDied(int pid, int uid) {
- mContext.getMainExecutor().execute(
- () -> MicrophoneForegroundServicesObserver.this.onProcessDied(pid));
- }
- };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java
deleted file mode 100644
index 9a2b4a93ac89..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java
+++ /dev/null
@@ -1,99 +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.systemui.statusbar.tv.micdisclosure;
-
-import static com.android.systemui.statusbar.tv.micdisclosure.AudioRecordingDisclosureBar.DEBUG;
-
-import android.annotation.UiThread;
-import android.app.AppOpsManager;
-import android.content.Context;
-import android.util.ArraySet;
-import android.util.Log;
-
-import java.util.Set;
-
-/**
- * The purpose of these class is to detect packages that are conducting audio recording (according
- * to {@link AppOpsManager}) and report this to {@link AudioRecordingDisclosureBar}.
- */
-class RecordAudioAppOpObserver extends AudioActivityObserver implements
- AppOpsManager.OnOpActiveChangedListener {
- private static final String TAG = "RecordAudioAppOpObserver";
-
- /**
- * Set of the applications that currently are conducting audio recording according to {@link
- * AppOpsManager}.
- */
- private final Set<String> mActiveAudioRecordingPackages = new ArraySet<>();
-
- RecordAudioAppOpObserver(Context context, OnAudioActivityStateChangeListener listener) {
- super(context, listener);
- }
-
- @Override
- void start() {
- if (DEBUG) {
- Log.d(TAG, "Start");
- }
-
- // Register AppOpsManager callback
- mContext.getSystemService(AppOpsManager.class)
- .startWatchingActive(
- new String[]{AppOpsManager.OPSTR_RECORD_AUDIO},
- mContext.getMainExecutor(),
- this);
- }
-
- @Override
- void stop() {
- if (DEBUG) {
- Log.d(TAG, "Stop");
- }
-
- // Unregister AppOpsManager callback
- mContext.getSystemService(AppOpsManager.class).stopWatchingActive(this);
-
- // Clean up state
- mActiveAudioRecordingPackages.clear();
- }
-
- @UiThread
- @Override
- Set<String> getActivePackages() {
- return mActiveAudioRecordingPackages;
- }
-
- @UiThread
- @Override
- public void onOpActiveChanged(String op, int uid, String packageName, boolean active) {
- if (DEBUG) {
- Log.d(TAG,
- "OP_RECORD_AUDIO active change, active=" + active + ", package="
- + packageName);
- }
-
- if (active) {
- if (mActiveAudioRecordingPackages.add(packageName)) {
- mListener.onAudioActivityStateChange(true, packageName);
- }
- } else {
- if (mActiveAudioRecordingPackages.remove(packageName)) {
- mListener.onAudioActivityStateChange(false, packageName);
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
index 0a3e83326e01..9effc6728bab 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
@@ -94,6 +94,7 @@ public class ThemeOverlayApplier implements Dumpable {
*/
static final List<String> THEME_CATEGORIES = Lists.newArrayList(
OVERLAY_CATEGORY_SYSTEM_PALETTE,
+ OVERLAY_CATEGORY_NEUTRAL_PALETTE,
OVERLAY_CATEGORY_ICON_LAUNCHER,
OVERLAY_CATEGORY_SHAPE,
OVERLAY_CATEGORY_FONT,
@@ -107,6 +108,7 @@ public class ThemeOverlayApplier implements Dumpable {
@VisibleForTesting
static final Set<String> SYSTEM_USER_CATEGORIES = Sets.newHashSet(
OVERLAY_CATEGORY_SYSTEM_PALETTE,
+ OVERLAY_CATEGORY_NEUTRAL_PALETTE,
OVERLAY_CATEGORY_ACCENT_COLOR,
OVERLAY_CATEGORY_FONT,
OVERLAY_CATEGORY_SHAPE,
@@ -129,8 +131,9 @@ public class ThemeOverlayApplier implements Dumpable {
mLauncherPackage = launcherPackage;
mThemePickerPackage = themePickerPackage;
mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet(
- OVERLAY_CATEGORY_SYSTEM_PALETTE, OVERLAY_CATEGORY_ACCENT_COLOR,
- OVERLAY_CATEGORY_FONT, OVERLAY_CATEGORY_SHAPE, OVERLAY_CATEGORY_ICON_ANDROID));
+ OVERLAY_CATEGORY_SYSTEM_PALETTE, OVERLAY_CATEGORY_NEUTRAL_PALETTE,
+ OVERLAY_CATEGORY_ACCENT_COLOR, OVERLAY_CATEGORY_FONT, OVERLAY_CATEGORY_SHAPE,
+ OVERLAY_CATEGORY_ICON_ANDROID));
mTargetPackageToCategories.put(SYSUI_PACKAGE,
Sets.newHashSet(OVERLAY_CATEGORY_ICON_SYSUI));
mTargetPackageToCategories.put(SETTINGS_PACKAGE,
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 1f222d80f014..028cbd084677 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -86,7 +86,7 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
protected static final int PRIMARY = 0;
protected static final int SECONDARY = 1;
- protected static final int NEUTRAL = 1;
+ protected static final int NEUTRAL = 2;
// If lock screen wallpaper colors should also be considered when selecting the theme.
// Doing this has performance impact, given that overlays would need to be swapped when
diff --git a/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java b/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java
index 79a197d9d409..a22793b05070 100644
--- a/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java
@@ -16,15 +16,18 @@
package com.android.systemui.util;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.DrawableWrapper;
+import android.graphics.drawable.InsetDrawable;
import android.util.AttributeSet;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.systemui.R;
import org.xmlpull.v1.XmlPullParser;
@@ -45,13 +48,18 @@ import java.io.IOException;
* @attr ref R.styleable#AlphaTintDrawableWrapper_tint
* @attr ref R.styleable#AlphaTintDrawableWrapper_alpha
*/
-public class AlphaTintDrawableWrapper extends DrawableWrapper {
+public class AlphaTintDrawableWrapper extends InsetDrawable {
private ColorStateList mTint;
private int[] mThemeAttrs;
/** No-arg constructor used by drawable inflation. */
public AlphaTintDrawableWrapper() {
- super(null);
+ super(null, 0);
+ }
+
+ AlphaTintDrawableWrapper(Drawable drawable, int[] themeAttrs) {
+ super(drawable, 0);
+ mThemeAttrs = themeAttrs;
}
@Override
@@ -74,7 +82,7 @@ public class AlphaTintDrawableWrapper extends DrawableWrapper {
public void applyTheme(Theme t) {
super.applyTheme(t);
- if (mThemeAttrs != null) {
+ if (mThemeAttrs != null && t != null) {
final TypedArray a = t.resolveAttributes(mThemeAttrs,
R.styleable.AlphaTintDrawableWrapper);
updateStateFromTypedArray(a);
@@ -92,9 +100,6 @@ public class AlphaTintDrawableWrapper extends DrawableWrapper {
}
private void updateStateFromTypedArray(@NonNull TypedArray a) {
- if (a.hasValue(R.styleable.AlphaTintDrawableWrapper_android_drawable)) {
- setDrawable(a.getDrawable(R.styleable.AlphaTintDrawableWrapper_android_drawable));
- }
if (a.hasValue(R.styleable.AlphaTintDrawableWrapper_android_tint)) {
mTint = a.getColorStateList(R.styleable.AlphaTintDrawableWrapper_android_tint);
}
@@ -109,4 +114,57 @@ public class AlphaTintDrawableWrapper extends DrawableWrapper {
getDrawable().mutate().setTintList(mTint);
}
}
+
+ @Nullable
+ @Override
+ public ConstantState getConstantState() {
+ return new AlphaTintState(super.getConstantState(), mThemeAttrs, getAlpha(), mTint);
+ }
+
+ static class AlphaTintState extends Drawable.ConstantState {
+
+ private ConstantState mWrappedState;
+ private int[] mThemeAttrs;
+ private int mAlpha;
+ private ColorStateList mColorStateList;
+
+ AlphaTintState(
+ ConstantState wrappedState,
+ int[] themeAttrs,
+ int alpha,
+ ColorStateList colorStateList
+ ) {
+ mWrappedState = wrappedState;
+ mThemeAttrs = themeAttrs;
+ mAlpha = alpha;
+ mColorStateList = colorStateList;
+ }
+
+ @NonNull
+ @Override
+ public Drawable newDrawable() {
+ return newDrawable(null, null);
+ }
+
+ @NonNull
+ @Override
+ public Drawable newDrawable(Resources res, Theme theme) {
+ DrawableWrapper wrapper = (DrawableWrapper) mWrappedState.newDrawable(res, theme);
+ AlphaTintDrawableWrapper alphaTintDrawableWrapper =
+ new AlphaTintDrawableWrapper(wrapper.getDrawable(), mThemeAttrs);
+ alphaTintDrawableWrapper.setTintList(mColorStateList);
+ alphaTintDrawableWrapper.setAlpha(mAlpha);
+ return alphaTintDrawableWrapper;
+ }
+
+ @Override
+ public boolean canApplyTheme() {
+ return true;
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mWrappedState.getChangingConfigurations();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt b/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt
index 1af2c9f46373..6aadd1020bce 100644
--- a/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt
@@ -17,15 +17,12 @@
package com.android.systemui.util
import android.content.res.Resources
-import android.content.res.TypedArray
import android.graphics.Canvas
import android.graphics.Path
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.graphics.drawable.DrawableWrapper
-import android.util.AttributeSet
-import com.android.systemui.R
-import org.xmlpull.v1.XmlPullParser
+import android.graphics.drawable.InsetDrawable
/**
* [DrawableWrapper] to use in the progress of a slider.
@@ -38,9 +35,9 @@ import org.xmlpull.v1.XmlPullParser
* is meant to be smaller than the rounded corner. The background should have rounded corners that
* are half of the height.
*/
-class RoundedCornerProgressDrawable(drawable: Drawable?) : DrawableWrapper(drawable) {
-
- constructor() : this(null)
+class RoundedCornerProgressDrawable @JvmOverloads constructor(
+ drawable: Drawable? = null
+) : InsetDrawable(drawable, 0) {
companion object {
private const val MAX_LEVEL = 10000 // Taken from Drawable
@@ -52,35 +49,11 @@ class RoundedCornerProgressDrawable(drawable: Drawable?) : DrawableWrapper(drawa
setClipPath(Rect())
}
- override fun inflate(
- r: Resources,
- parser: XmlPullParser,
- attrs: AttributeSet,
- theme: Resources.Theme?
- ) {
- val a = obtainAttributes(r, theme, attrs, R.styleable.RoundedCornerProgressDrawable)
-
- // Inflation will advance the XmlPullParser and AttributeSet.
- super.inflate(r, parser, attrs, theme)
-
- updateStateFromTypedArray(a)
- if (drawable == null) {
- throw IllegalStateException("${this::class.java.simpleName} needs a drawable")
- }
- a.recycle()
- }
-
override fun onLayoutDirectionChanged(layoutDirection: Int): Boolean {
onLevelChange(level)
return super.onLayoutDirectionChanged(layoutDirection)
}
- private fun updateStateFromTypedArray(a: TypedArray) {
- if (a.hasValue(R.styleable.RoundedCornerProgressDrawable_android_drawable)) {
- setDrawable(a.getDrawable(R.styleable.RoundedCornerProgressDrawable_android_drawable))
- }
- }
-
override fun onBoundsChange(bounds: Rect) {
setClipPath(bounds)
super.onBoundsChange(bounds)
@@ -115,4 +88,24 @@ class RoundedCornerProgressDrawable(drawable: Drawable?) : DrawableWrapper(drawa
super.draw(canvas)
canvas.restore()
}
+
+ override fun getConstantState(): ConstantState? {
+ // This should not be null as it was created with a state in the constructor.
+ return RoundedCornerState(super.getConstantState()!!)
+ }
+
+ private class RoundedCornerState(private val wrappedState: ConstantState) : ConstantState() {
+ override fun newDrawable(): Drawable {
+ return newDrawable(null, null)
+ }
+
+ override fun newDrawable(res: Resources?, theme: Resources.Theme?): Drawable {
+ val wrapper = wrappedState.newDrawable(res, theme) as DrawableWrapper
+ return RoundedCornerProgressDrawable(wrapper.drawable)
+ }
+
+ override fun getChangingConfigurations(): Int {
+ return wrappedState.changingConfigurations
+ }
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index 06806d0e6ab6..6a648bdf8cd4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -347,6 +347,7 @@ public class ProximitySensor implements ThresholdSensor {
public void check(long timeoutMs, Consumer<Boolean> callback) {
if (!mSensor.isLoaded()) {
callback.accept(null);
+ return;
}
mCallbacks.add(callback);
if (!mRegistered.getAndSet(true)) {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index fba0b0079012..4611fe03e157 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -31,6 +31,7 @@ import android.view.WindowManager;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.R;
import com.android.systemui.dagger.WMComponent;
import com.android.systemui.dagger.WMSingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -97,7 +98,12 @@ import dagger.Provides;
@Module
public abstract class WMShellBaseModule {
- private static final boolean ENABLE_SHELL_MAIN_THREAD = false;
+ /**
+ * Returns whether to enable a separate shell thread for the shell features.
+ */
+ private static boolean enableShellMainThread(Context context) {
+ return context.getResources().getBoolean(R.bool.config_enableShellMainThread);
+ }
//
// Shell Concurrency - Components used for managing threading in the Shell and SysUI
@@ -120,8 +126,8 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
@ShellMainThread
- public static Handler provideShellMainHandler(@Main Handler sysuiMainHandler) {
- if (ENABLE_SHELL_MAIN_THREAD) {
+ public static Handler provideShellMainHandler(Context context, @Main Handler sysuiMainHandler) {
+ if (enableShellMainThread(context)) {
HandlerThread mainThread = new HandlerThread("wmshell.main");
mainThread.start();
return mainThread.getThreadHandler();
@@ -135,9 +141,9 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
@ShellMainThread
- public static ShellExecutor provideShellMainExecutor(@ShellMainThread Handler mainHandler,
- @Main ShellExecutor sysuiMainExecutor) {
- if (ENABLE_SHELL_MAIN_THREAD) {
+ public static ShellExecutor provideShellMainExecutor(Context context,
+ @ShellMainThread Handler mainHandler, @Main ShellExecutor sysuiMainExecutor) {
+ if (enableShellMainThread(context)) {
return new HandlerExecutor(mainHandler);
}
return sysuiMainExecutor;
@@ -380,9 +386,9 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
static Transitions provideTransitions(ShellTaskOrganizer organizer, TransactionPool pool,
- @ShellMainThread ShellExecutor mainExecutor,
+ Context context, @ShellMainThread ShellExecutor mainExecutor,
@ShellAnimationThread ShellExecutor animExecutor) {
- return new Transitions(organizer, pool, mainExecutor, animExecutor);
+ return new Transitions(organizer, pool, context, mainExecutor, animExecutor);
}
//
@@ -409,10 +415,11 @@ public abstract class WMShellBaseModule {
ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
- @ShellMainThread ShellExecutor mainExecutor) {
+ @ShellMainThread ShellExecutor mainExecutor,
+ DisplayImeController displayImeController) {
if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) {
return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context,
- rootTaskDisplayAreaOrganizer, mainExecutor));
+ rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController));
} else {
return Optional.empty();
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 997b488a627f..754b6a6435b4 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -104,9 +104,10 @@ public class WMShellModule {
@Provides
static AppPairsController provideAppPairs(ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue, DisplayController displayController,
- @ShellMainThread ShellExecutor mainExecutor) {
+ @ShellMainThread ShellExecutor mainExecutor,
+ DisplayImeController displayImeController) {
return new AppPairsController(shellTaskOrganizer, syncQueue, displayController,
- mainExecutor);
+ mainExecutor, displayImeController);
}
//
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 14b4d0262f60..854be1f76722 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -26,16 +26,11 @@ import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.testing.TestableResources;
-import android.view.View;
-import android.view.ViewGroup;
import android.view.WindowInsetsController;
-import android.widget.FrameLayout;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
@@ -50,21 +45,12 @@ import org.mockito.junit.MockitoRule;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper()
public class KeyguardSecurityContainerTest extends SysuiTestCase {
- private static final int SCREEN_WIDTH = 1600;
- private static final int FAKE_MEASURE_SPEC =
- View.MeasureSpec.makeMeasureSpec(SCREEN_WIDTH, View.MeasureSpec.EXACTLY);
-
- private static final SecurityMode ONE_HANDED_SECURITY_MODE = SecurityMode.PIN;
- private static final SecurityMode TWO_HANDED_SECURITY_MODE = SecurityMode.Password;
-
-
@Rule
public MockitoRule mRule = MockitoJUnit.rule();
@Mock
private WindowInsetsController mWindowInsetsController;
-
@Mock
private KeyguardSecurityViewFlipper mSecurityViewFlipper;
@@ -72,18 +58,9 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
@Before
public void setup() {
- // Needed here, otherwise when mKeyguardSecurityContainer is created below, it'll cache
- // the real references (rather than the TestableResources that this call creates).
- mContext.ensureTestableResources();
- FrameLayout.LayoutParams securityViewFlipperLayoutParams = new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
-
when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
- when(mSecurityViewFlipper.getLayoutParams()).thenReturn(securityViewFlipperLayoutParams);
mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext());
mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
- mKeyguardSecurityContainer.addView(mSecurityViewFlipper, new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
@Test
@@ -92,75 +69,4 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
verify(mWindowInsetsController).controlWindowInsetsAnimation(eq(ime()), anyLong(), any(),
any(), any());
}
-
- @Test
- public void onMeasure_usesFullWidthWithoutOneHandedMode() {
- setUpKeyguard(
- /* deviceConfigCanUseOneHandedKeyguard= */false,
- /* sysuiResourceCanUseOneHandedKeyguard= */ false,
- ONE_HANDED_SECURITY_MODE);
-
- mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
-
- verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
- }
-
- @Test
- public void onMeasure_usesFullWidthWithDeviceFlagDisabled() {
- setUpKeyguard(
- /* deviceConfigCanUseOneHandedKeyguard= */false,
- /* sysuiResourceCanUseOneHandedKeyguard= */ true,
- ONE_HANDED_SECURITY_MODE);
-
- mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
- verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
- }
-
- @Test
- public void onMeasure_usesFullWidthWithSysUIFlagDisabled() {
- setUpKeyguard(
- /* deviceConfigCanUseOneHandedKeyguard= */true,
- /* sysuiResourceCanUseOneHandedKeyguard= */ false,
- ONE_HANDED_SECURITY_MODE);
-
- mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
- verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
- }
-
- @Test
- public void onMeasure_usesHalfWidthWithFlagsEnabled() {
- setUpKeyguard(
- /* deviceConfigCanUseOneHandedKeyguard= */true,
- /* sysuiResourceCanUseOneHandedKeyguard= */ true,
- ONE_HANDED_SECURITY_MODE);
-
- int halfWidthMeasureSpec =
- View.MeasureSpec.makeMeasureSpec(SCREEN_WIDTH / 2, View.MeasureSpec.EXACTLY);
- mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
-
- verify(mSecurityViewFlipper).measure(halfWidthMeasureSpec, FAKE_MEASURE_SPEC);
- }
-
- @Test
- public void onMeasure_usesFullWidthForFullScreenIme() {
- setUpKeyguard(
- /* deviceConfigCanUseOneHandedKeyguard= */true,
- /* sysuiResourceCanUseOneHandedKeyguard= */ true,
- TWO_HANDED_SECURITY_MODE);
-
- mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
- verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
- }
-
- private void setUpKeyguard(
- boolean deviceConfigCanUseOneHandedKeyguard,
- boolean sysuiResourceCanUseOneHandedKeyguard,
- SecurityMode securityMode) {
- TestableResources testableResources = mContext.getOrCreateTestableResources();
- testableResources.addOverride(com.android.internal.R.bool.config_enableOneHandedKeyguard,
- deviceConfigCanUseOneHandedKeyguard);
- testableResources.addOverride(R.bool.can_use_one_handed_bouncer,
- sysuiResourceCanUseOneHandedKeyguard);
- mKeyguardSecurityContainer.updateLayoutForSecurityMode(securityMode);
- }
-}
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
index d79155cbb2fc..c8e939609e87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.people;
+import static android.app.Notification.CATEGORY_MISSED_CALL;
import static android.app.people.ConversationStatus.ACTIVITY_BIRTHDAY;
import static android.app.people.ConversationStatus.ACTIVITY_GAME;
import static android.app.people.ConversationStatus.ACTIVITY_NEW_STORY;
@@ -113,6 +114,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
private static final Uri URI = Uri.parse("fake_uri");
private static final Icon ICON = Icon.createWithResource("package", R.drawable.ic_android);
private static final String GAME_DESCRIPTION = "Playing a game!";
+ private static final CharSequence MISSED_CALL = "Custom missed call message";
private static final String NAME = "username";
private static final Person PERSON = new Person.Builder()
.setName("name")
@@ -346,7 +348,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
.build();
Notification.MessagingStyle.Message lastMessage =
- PeopleSpaceUtils.getLastMessagingStyleMessage(sbn);
+ PeopleSpaceUtils.getLastMessagingStyleMessage(sbn.getNotification());
assertThat(lastMessage).isNull();
}
@@ -447,7 +449,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
.build();
Notification.MessagingStyle.Message lastMessage =
- PeopleSpaceUtils.getLastMessagingStyleMessage(sbn);
+ PeopleSpaceUtils.getLastMessagingStyleMessage(sbn.getNotification());
assertThat(lastMessage.getText().toString()).isEqualTo(NOTIFICATION_TEXT_2);
}
@@ -465,7 +467,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
.setUid(0)
.build();
PeopleSpaceTile actual = PeopleSpaceUtils
- .augmentTileFromNotification(tile, sbn);
+ .augmentTileFromNotification(mContext, tile, sbn);
assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_TEXT_2);
}
@@ -483,9 +485,8 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
.setUid(0)
.build();
PeopleSpaceTile actual = PeopleSpaceUtils
- .augmentTileFromNotification(tile, sbn);
+ .augmentTileFromNotification(mContext, tile, sbn);
- assertThat(actual.getNotificationKey()).isEqualTo(null);
assertThat(actual.getNotificationContent()).isEqualTo(null);
}
@@ -498,7 +499,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
.setUid(0)
.build();
PeopleSpaceTile actual = PeopleSpaceUtils
- .augmentTileFromVisibleNotifications(tile,
+ .augmentTileFromVisibleNotifications(mContext, tile,
Map.of(PeopleSpaceUtils.getKey(mNotificationEntry1), mNotificationEntry1));
assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_TEXT_2);
@@ -513,7 +514,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
.setUid(0)
.build();
PeopleSpaceTile actual = PeopleSpaceUtils
- .augmentTileFromVisibleNotifications(tile,
+ .augmentTileFromVisibleNotifications(mContext, tile,
Map.of(PeopleSpaceUtils.getKey(mNotificationEntry1), mNotificationEntry1));
assertThat(actual.getNotificationContent()).isEqualTo(null);
@@ -528,7 +529,8 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
.setUid(0)
.build();
List<PeopleSpaceTile> actualList = PeopleSpaceUtils
- .augmentTilesFromVisibleNotifications(List.of(tile), mNotificationEntryManager);
+ .augmentTilesFromVisibleNotifications(
+ mContext, List.of(tile), mNotificationEntryManager);
assertThat(actualList.size()).isEqualTo(1);
assertThat(actualList.get(0).getNotificationContent().toString())
@@ -552,7 +554,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
.setUid(0)
.build();
List<PeopleSpaceTile> actualList = PeopleSpaceUtils
- .augmentTilesFromVisibleNotifications(List.of(tile1, tile2),
+ .augmentTilesFromVisibleNotifications(mContext, List.of(tile1, tile2),
mNotificationEntryManager);
assertThat(actualList.size()).isEqualTo(2);
@@ -763,6 +765,33 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
}
@Test
+ public void testCreateRemoteViewsWithMissedCallNotification() {
+ PeopleSpaceTile tileWithMissedCallNotification = PERSON_TILE.toBuilder()
+ .setNotificationDataUri(null)
+ .setNotificationCategory(CATEGORY_MISSED_CALL)
+ .setNotificationContent(MISSED_CALL)
+ .build();
+ RemoteViews views = PeopleSpaceUtils.createRemoteViews(mContext,
+ tileWithMissedCallNotification, 0);
+ View result = views.apply(mContext, null);
+
+ TextView name = (TextView) result.findViewById(R.id.name);
+ assertEquals(name.getText(), NAME);
+ // Has availability.
+ View availability = result.findViewById(R.id.availability);
+ assertEquals(View.GONE, availability.getVisibility());
+ // Has new story.
+ View personIcon = result.findViewById(R.id.person_icon_only);
+ View personIconWithStory = result.findViewById(R.id.person_icon_with_story);
+ assertEquals(View.VISIBLE, personIcon.getVisibility());
+ assertEquals(View.GONE, personIconWithStory.getVisibility());
+ // Has status.
+ TextView statusContent = (TextView) result.findViewById(R.id.status);
+ assertEquals(statusContent.getText(), MISSED_CALL);
+ }
+
+
+ @Test
public void testCreateRemoteViewsWithNotificationTemplate() {
PeopleSpaceTile tileWithStatusAndNotification = PERSON_TILE.toBuilder()
.setNotificationDataUri(null)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index 9470141178dd..1c8324c524f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.people.widget;
+import static android.app.Notification.CATEGORY_MISSED_CALL;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
@@ -167,7 +168,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
int[] widgetIdsArray = {};
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
- StatusBarNotification sbn = createConversationNotification(OTHER_SHORTCUT_ID);
+ StatusBarNotification sbn = createNotification(
+ OTHER_SHORTCUT_ID, /* isMessagingStyle = */ false, /* isMissedCall = */ false);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
.setSbn(sbn)
.setId(1));
@@ -207,7 +209,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
StatusBarNotification sbnWithoutPackageName = new SbnBuilder()
- .setNotification(createMessagingStyleNotification(SHORTCUT_ID))
+ .setNotification(createMessagingStyleNotification(
+ SHORTCUT_ID, /* isMessagingStyle = */ false, /* isMissedCall = */ false))
.build();
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
.setSbn(sbnWithoutPackageName)
@@ -256,7 +259,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
- StatusBarNotification sbn = createConversationNotification(OTHER_SHORTCUT_ID);
+ StatusBarNotification sbn = createNotification(
+ OTHER_SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
.setSbn(sbn)
.setId(1));
@@ -276,7 +280,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
StatusBarNotification sbnWithDifferentPackageName = new SbnBuilder()
- .setNotification(createMessagingStyleNotification(SHORTCUT_ID))
+ .setNotification(createMessagingStyleNotification(
+ SHORTCUT_ID, /* isMessagingStyle = */ false, /* isMissedCall = */ false))
.setPkg(TEST_PACKAGE_B)
.build();
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
@@ -295,7 +300,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
- StatusBarNotification sbn = createConversationNotification(OTHER_SHORTCUT_ID);
+ StatusBarNotification sbn = createNotification(
+ OTHER_SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
.setSbn(sbn)
.setId(1));
@@ -315,7 +321,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
StatusBarNotification sbnWithDifferentPackageName = new SbnBuilder()
- .setNotification(createMessagingStyleNotification(SHORTCUT_ID))
+ .setNotification(createMessagingStyleNotification(
+ SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false))
.setPkg(TEST_PACKAGE_B)
.build();
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
@@ -337,7 +344,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
- .setSbn(createConversationNotification(SHORTCUT_ID))
+ .setSbn(createNotification(
+ SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false))
.setId(1));
mClock.advanceTime(MIN_LINGER_DURATION);
@@ -367,7 +375,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
- .setSbn(createConversationNotification(SHORTCUT_ID))
+ .setSbn(createNotification(
+ SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false))
.setId(1));
mClock.advanceTime(MIN_LINGER_DURATION);
@@ -400,7 +409,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
PeopleSpaceUtils.removeStorageForTile(mContext, SECOND_WIDGET_ID_WITH_SHORTCUT);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
- .setSbn(createConversationNotification(SHORTCUT_ID))
+ .setSbn(createNotification(
+ SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false))
.setId(1));
mClock.advanceTime(MIN_LINGER_DURATION);
@@ -417,33 +427,52 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
}
@Test
- public void testDoNotUpdateNotificationPostedWithoutMessagesIfExistingTile()
+ public void testUpdateMissedCallNotificationWithoutContentPostedIfExistingTile()
throws Exception {
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, WIDGET_ID_WITH_SHORTCUT);
- Notification notificationWithoutMessagingStyle = new Notification.Builder(mContext)
- .setContentTitle("TEST_TITLE")
- .setContentText("TEST_TEXT")
- .setShortcutId(SHORTCUT_ID)
- .build();
- StatusBarNotification sbn = new SbnBuilder()
- .setNotification(notificationWithoutMessagingStyle)
- .setPkg(TEST_PACKAGE_A)
- .setUid(0)
- .build();
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
- .setSbn(sbn)
+ .setSbn(createNotification(
+ SHORTCUT_ID, /* isMessagingStyle = */ false, /* isMissedCall = */ true))
.setId(1));
mClock.advanceTime(MIN_LINGER_DURATION);
verify(mAppWidgetManager, times(1))
.updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
mBundleArgumentCaptor.capture());
- Bundle options = requireNonNull(mBundleArgumentCaptor.getValue());
- assertThat((PeopleSpaceTile) options.getParcelable(OPTIONS_PEOPLE_SPACE_TILE))
- .isEqualTo(PERSON_TILE);
+ Bundle bundle = requireNonNull(mBundleArgumentCaptor.getValue());
+
+ PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_SPACE_TILE);
+ assertThat(tile.getNotificationKey()).isEqualTo(NOTIFICATION_KEY);
+ assertThat(tile.getNotificationContent())
+ .isEqualTo(mContext.getString(R.string.missed_call));
+ verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
+ any());
+ }
+
+ @Test
+ public void testUpdateMissedCallNotificationWithContentPostedIfExistingTile()
+ throws Exception {
+ int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
+ when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, WIDGET_ID_WITH_SHORTCUT);
+
+ NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setSbn(createNotification(
+ SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ true))
+ .setId(1));
+ mClock.advanceTime(MIN_LINGER_DURATION);
+
+ verify(mAppWidgetManager, times(1))
+ .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
+ mBundleArgumentCaptor.capture());
+ Bundle bundle = requireNonNull(mBundleArgumentCaptor.getValue());
+
+ PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_SPACE_TILE);
+ assertThat(tile.getNotificationKey()).isEqualTo(NOTIFICATION_KEY);
+ assertThat(tile.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT);
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
any());
}
@@ -453,7 +482,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
- StatusBarNotification sbn = createConversationNotification(SHORTCUT_ID);
+ StatusBarNotification sbn = createNotification(
+ SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
.setSbn(sbn)
.setId(1));
@@ -483,21 +513,29 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
return convo;
}
- private Notification createMessagingStyleNotification(String shortcutId) {
- return new Notification.Builder(mContext)
+ private Notification createMessagingStyleNotification(String shortcutId,
+ boolean isMessagingStyle, boolean isMissedCall) {
+ Notification.Builder builder = new Notification.Builder(mContext)
.setContentTitle("TEST_TITLE")
.setContentText("TEST_TEXT")
- .setShortcutId(shortcutId)
- .setStyle(new Notification.MessagingStyle(PERSON)
- .addMessage(
- new Notification.MessagingStyle.Message(NOTIFICATION_CONTENT, 10,
- PERSON))
- )
- .build();
+ .setShortcutId(shortcutId);
+ if (isMessagingStyle) {
+ builder.setStyle(new Notification.MessagingStyle(PERSON)
+ .addMessage(
+ new Notification.MessagingStyle.Message(NOTIFICATION_CONTENT, 10,
+ PERSON))
+ );
+ }
+ if (isMissedCall) {
+ builder.setCategory(CATEGORY_MISSED_CALL);
+ }
+ return builder.build();
}
- private StatusBarNotification createConversationNotification(String shortcutId) {
- Notification notification = createMessagingStyleNotification(shortcutId);
+ private StatusBarNotification createNotification(String shortcutId,
+ boolean isMessagingStyle, boolean isMissedCall) {
+ Notification notification = createMessagingStyleNotification(
+ shortcutId, isMessagingStyle, isMissedCall);
return new SbnBuilder()
.setNotification(notification)
.setPkg(TEST_PACKAGE_A)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index ce0f1220fc88..9a5482c33501 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -377,8 +377,6 @@ public class NotifCollectionTest extends SysuiTestCase {
// THEN we send the dismissal to system server
verify(mStatusBarService).onNotificationClear(
notif2.sbn.getPackageName(),
- notif2.sbn.getTag(),
- 88,
notif2.sbn.getUser().getIdentifier(),
notif2.sbn.getKey(),
stats.dismissalSurface,
@@ -528,8 +526,6 @@ public class NotifCollectionTest extends SysuiTestCase {
// THEN we never send the dismissal to system server
verify(mStatusBarService, never()).onNotificationClear(
notif.sbn.getPackageName(),
- notif.sbn.getTag(),
- 47,
notif.sbn.getUser().getIdentifier(),
notif.sbn.getKey(),
stats.dismissalSurface,
@@ -566,8 +562,6 @@ public class NotifCollectionTest extends SysuiTestCase {
// THEN the notification is never sent to system server to dismiss
verify(mStatusBarService, never()).onNotificationClear(
eq(notif.sbn.getPackageName()),
- eq(notif.sbn.getTag()),
- eq(47),
eq(notif.sbn.getUser().getIdentifier()),
eq(notif.sbn.getKey()),
anyInt(),
@@ -596,8 +590,6 @@ public class NotifCollectionTest extends SysuiTestCase {
// THEN we send the dismissal to system server
verify(mStatusBarService).onNotificationClear(
eq(notif.sbn.getPackageName()),
- eq(notif.sbn.getTag()),
- eq(47),
eq(notif.sbn.getUser().getIdentifier()),
eq(notif.sbn.getKey()),
anyInt(),
@@ -1125,8 +1117,6 @@ public class NotifCollectionTest extends SysuiTestCase {
// THEN we send the dismissals to system server
verify(mStatusBarService).onNotificationClear(
notif1.sbn.getPackageName(),
- notif1.sbn.getTag(),
- 47,
notif1.sbn.getUser().getIdentifier(),
notif1.sbn.getKey(),
stats1.dismissalSurface,
@@ -1135,8 +1125,6 @@ public class NotifCollectionTest extends SysuiTestCase {
verify(mStatusBarService).onNotificationClear(
notif2.sbn.getPackageName(),
- notif2.sbn.getTag(),
- 88,
notif2.sbn.getUser().getIdentifier(),
notif2.sbn.getKey(),
stats2.dismissalSurface,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
index 45828c3f73ad..e798207c6947 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
@@ -23,6 +23,7 @@ import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_IC
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_SETTINGS;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_SYSUI;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_THEME_PICKER;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_NEUTRAL_PALETTE;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SHAPE;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE;
import static com.android.systemui.theme.ThemeOverlayApplier.SETTINGS_PACKAGE;
@@ -114,6 +115,8 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
ANDROID_PACKAGE, OVERLAY_CATEGORY_ACCENT_COLOR, false),
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_SYSTEM_PALETTE,
ANDROID_PACKAGE, OVERLAY_CATEGORY_SYSTEM_PALETTE, false),
+ createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_NEUTRAL_PALETTE,
+ ANDROID_PACKAGE, OVERLAY_CATEGORY_NEUTRAL_PALETTE, false),
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_FONT,
ANDROID_PACKAGE, OVERLAY_CATEGORY_FONT, false),
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_SHAPE,
@@ -124,6 +127,8 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
ANDROID_PACKAGE, OVERLAY_CATEGORY_ACCENT_COLOR, true),
createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_SYSTEM_PALETTE,
ANDROID_PACKAGE, OVERLAY_CATEGORY_SYSTEM_PALETTE, true),
+ createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_NEUTRAL_PALETTE,
+ ANDROID_PACKAGE, OVERLAY_CATEGORY_NEUTRAL_PALETTE, true),
createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_FONT,
ANDROID_PACKAGE, OVERLAY_CATEGORY_FONT, true),
createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_SHAPE,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
index c5a197eef2d4..242fe9f5fffe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.util.sensors;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@@ -86,6 +88,29 @@ public class ProximityCheckTest extends SysuiTestCase {
}
@Test
+ public void testNotLoaded() {
+ mFakeProximitySensor.setSensorAvailable(false);
+
+ assertThat(mTestableCallback.mLastResult).isNull();
+ assertThat(mTestableCallback.mNumCalls).isEqualTo(0);
+
+ mProximityCheck.check(100, mTestableCallback);
+
+ assertThat(mTestableCallback.mLastResult).isNull();
+ assertThat(mTestableCallback.mNumCalls).isEqualTo(1);
+
+ mFakeProximitySensor.setSensorAvailable(true);
+
+ mProximityCheck.check(100, mTestableCallback);
+
+ mFakeProximitySensor.setLastEvent(new ProximitySensor.ThresholdSensorEvent(true, 0));
+ mFakeProximitySensor.alertListeners();
+
+ assertThat(mTestableCallback.mLastResult).isNotNull();
+ assertThat(mTestableCallback.mNumCalls).isEqualTo(2);
+ }
+
+ @Test
public void testProxDoesntCancelOthers() {
assertFalse(mFakeProximitySensor.isRegistered());
// We don't need our "other" listener to do anything. Just ensure our sensor is registered.
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java
index 6dcad255eee4..3502baa99b6d 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java
@@ -23,7 +23,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
+import android.net.VpnManager;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
@@ -42,7 +42,7 @@ public class AlwaysOnDisconnectedDialog extends AlertActivity
private static final String TAG = "VpnDisconnected";
- private ConnectivityManager mService;
+ private VpnManager mService;
private int mUserId;
private String mVpnPackage;
@@ -51,8 +51,8 @@ public class AlwaysOnDisconnectedDialog extends AlertActivity
super.onCreate(savedInstanceState);
mUserId = UserHandle.myUserId();
- final ConnectivityManager cm = getSystemService(ConnectivityManager.class);
- mVpnPackage = cm.getAlwaysOnVpnPackageForUser(mUserId);
+ final VpnManager vm = getSystemService(VpnManager.class);
+ mVpnPackage = vm.getAlwaysOnVpnPackageForUser(mUserId);
if (mVpnPackage == null) {
finish();
return;
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
index aab01d03b96d..fb2367843fc1 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
@@ -21,7 +21,6 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
-import android.net.ConnectivityManager;
import android.net.VpnManager;
import android.os.Bundle;
import android.os.UserHandle;
@@ -45,7 +44,6 @@ public class ConfirmDialog extends AlertActivity
private String mPackage;
- private ConnectivityManager mCm; // TODO: switch entirely to VpnManager once VPN code moves
private VpnManager mVm;
public ConfirmDialog() {
@@ -60,7 +58,6 @@ public class ConfirmDialog extends AlertActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPackage = getCallingPackage();
- mCm = getSystemService(ConnectivityManager.class);
mVm = getSystemService(VpnManager.class);
if (mVm.prepareVpn(mPackage, null, UserHandle.myUserId())) {
@@ -72,7 +69,7 @@ public class ConfirmDialog extends AlertActivity
finish();
return;
}
- final String alwaysOnVpnPackage = mCm.getAlwaysOnVpnPackageForUser(UserHandle.myUserId());
+ final String alwaysOnVpnPackage = mVm.getAlwaysOnVpnPackageForUser(UserHandle.myUserId());
// Can't prepare new vpn app when another vpn is always-on
if (alwaysOnVpnPackage != null && !alwaysOnVpnPackage.equals(mPackage)) {
finish();
diff --git a/packages/overlays/AccentColorAmethystOverlay/Android.bp b/packages/overlays/AccentColorAmethystOverlay/Android.bp
index 7519b12dd2d9..186d770c09a5 100644
--- a/packages/overlays/AccentColorAmethystOverlay/Android.bp
+++ b/packages/overlays/AccentColorAmethystOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "AccentColorAmethystOverlay",
theme: "AccentColorAmethyst",
diff --git a/packages/overlays/AccentColorAquamarineOverlay/Android.bp b/packages/overlays/AccentColorAquamarineOverlay/Android.bp
index 4469b36cfbc5..7fd64f374522 100644
--- a/packages/overlays/AccentColorAquamarineOverlay/Android.bp
+++ b/packages/overlays/AccentColorAquamarineOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "AccentColorAquamarineOverlay",
theme: "AccentColorAquamarine",
diff --git a/packages/overlays/AccentColorBlackOverlay/Android.bp b/packages/overlays/AccentColorBlackOverlay/Android.bp
index bfee26ea52dd..ac923ebd7cd9 100644
--- a/packages/overlays/AccentColorBlackOverlay/Android.bp
+++ b/packages/overlays/AccentColorBlackOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "AccentColorBlackOverlay",
theme: "AccentColorBlack",
diff --git a/packages/overlays/AccentColorCarbonOverlay/Android.bp b/packages/overlays/AccentColorCarbonOverlay/Android.bp
index 47f66dd9ba62..f4f1b8b50a1e 100644
--- a/packages/overlays/AccentColorCarbonOverlay/Android.bp
+++ b/packages/overlays/AccentColorCarbonOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "AccentColorCarbonOverlay",
theme: "AccentColorCarbon",
diff --git a/packages/overlays/AccentColorCinnamonOverlay/Android.bp b/packages/overlays/AccentColorCinnamonOverlay/Android.bp
index 8250315256b8..53899bfefd98 100644
--- a/packages/overlays/AccentColorCinnamonOverlay/Android.bp
+++ b/packages/overlays/AccentColorCinnamonOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "AccentColorCinnamonOverlay",
theme: "AccentColorCinnamon",
diff --git a/packages/overlays/AccentColorGreenOverlay/Android.bp b/packages/overlays/AccentColorGreenOverlay/Android.bp
index 15b50c76aa38..5b1f7447a7ca 100644
--- a/packages/overlays/AccentColorGreenOverlay/Android.bp
+++ b/packages/overlays/AccentColorGreenOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "AccentColorGreenOverlay",
theme: "AccentColorGreen",
diff --git a/packages/overlays/AccentColorOceanOverlay/Android.bp b/packages/overlays/AccentColorOceanOverlay/Android.bp
index 6ad63bc92816..a85883044dc2 100644
--- a/packages/overlays/AccentColorOceanOverlay/Android.bp
+++ b/packages/overlays/AccentColorOceanOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "AccentColorOceanOverlay",
theme: "AccentColorOcean",
diff --git a/packages/overlays/AccentColorOrchidOverlay/Android.bp b/packages/overlays/AccentColorOrchidOverlay/Android.bp
index b66933397e12..31ed30921664 100644
--- a/packages/overlays/AccentColorOrchidOverlay/Android.bp
+++ b/packages/overlays/AccentColorOrchidOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "AccentColorOrchidOverlay",
theme: "AccentColorOrchid",
diff --git a/packages/overlays/AccentColorPaletteOverlay/Android.bp b/packages/overlays/AccentColorPaletteOverlay/Android.bp
index eeefd1623a49..a6cc1dec37dd 100644
--- a/packages/overlays/AccentColorPaletteOverlay/Android.bp
+++ b/packages/overlays/AccentColorPaletteOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "AccentColorPaletteOverlay",
theme: "AccentColorPalette",
diff --git a/packages/overlays/AccentColorPurpleOverlay/Android.bp b/packages/overlays/AccentColorPurpleOverlay/Android.bp
index ead95df18d9e..80e0ab1159b7 100644
--- a/packages/overlays/AccentColorPurpleOverlay/Android.bp
+++ b/packages/overlays/AccentColorPurpleOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "AccentColorPurpleOverlay",
theme: "AccentColorPurple",
diff --git a/packages/overlays/AccentColorSandOverlay/Android.bp b/packages/overlays/AccentColorSandOverlay/Android.bp
index f70578a1ec38..771abca4c3f6 100644
--- a/packages/overlays/AccentColorSandOverlay/Android.bp
+++ b/packages/overlays/AccentColorSandOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "AccentColorSandOverlay",
theme: "AccentColorSand",
diff --git a/packages/overlays/AccentColorSpaceOverlay/Android.bp b/packages/overlays/AccentColorSpaceOverlay/Android.bp
index 1d713df3cfdd..8e4abacf1ef2 100644
--- a/packages/overlays/AccentColorSpaceOverlay/Android.bp
+++ b/packages/overlays/AccentColorSpaceOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "AccentColorSpaceOverlay",
theme: "AccentColorSpace",
diff --git a/packages/overlays/AccentColorTangerineOverlay/Android.bp b/packages/overlays/AccentColorTangerineOverlay/Android.bp
index d3b1e54fe823..75c708ec9fe7 100644
--- a/packages/overlays/AccentColorTangerineOverlay/Android.bp
+++ b/packages/overlays/AccentColorTangerineOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "AccentColorTangerineOverlay",
theme: "AccentColorTangerine",
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.bp b/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.bp
index b8def98791be..8e03809cadf0 100644
--- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.bp
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
runtime_resource_overlay {
name: "DisplayCutoutEmulationCornerOverlay",
theme: "DisplayCutoutEmulationCorner",
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.bp b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.bp
index b64ddfd82c05..afa5b649a432 100644
--- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.bp
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
runtime_resource_overlay {
name: "DisplayCutoutEmulationDoubleOverlay",
theme: "DisplayCutoutEmulationDouble",
diff --git a/packages/overlays/DisplayCutoutEmulationHoleOverlay/Android.bp b/packages/overlays/DisplayCutoutEmulationHoleOverlay/Android.bp
index 86cfebfbd0db..eae907db00ff 100644
--- a/packages/overlays/DisplayCutoutEmulationHoleOverlay/Android.bp
+++ b/packages/overlays/DisplayCutoutEmulationHoleOverlay/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
runtime_resource_overlay {
name: "DisplayCutoutEmulationHoleOverlay",
theme: "DisplayCutoutEmulationHole",
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.bp b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.bp
index 28ad9db119cb..25bc676bb027 100644
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.bp
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
runtime_resource_overlay {
name: "DisplayCutoutEmulationNarrowOverlay",
theme: "DisplayCutoutEmulationNarrow",
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.bp b/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.bp
index cd00386658ed..2828612254a3 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.bp
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
runtime_resource_overlay {
name: "DisplayCutoutEmulationTallOverlay",
theme: "DisplayCutoutEmulationTall",
diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/Android.bp b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/Android.bp
index d5fe683d5e55..66be777649ed 100644
--- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/Android.bp
+++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
runtime_resource_overlay {
name: "DisplayCutoutEmulationWaterfallOverlay",
theme: "DisplayCutoutEmulationWaterfall",
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.bp b/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.bp
index 0157ec48ee3a..e71cefe7643e 100644
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.bp
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
runtime_resource_overlay {
name: "DisplayCutoutEmulationWideOverlay",
theme: "DisplayCutoutEmulationWide",
diff --git a/packages/overlays/FontNotoSerifSourceOverlay/Android.bp b/packages/overlays/FontNotoSerifSourceOverlay/Android.bp
index 7fd145b57934..231295b41a27 100644
--- a/packages/overlays/FontNotoSerifSourceOverlay/Android.bp
+++ b/packages/overlays/FontNotoSerifSourceOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "FontNotoSerifSourceOverlay",
theme: "FontNotoSerifSource",
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/Android.bp b/packages/overlays/IconPackCircularAndroidOverlay/Android.bp
index cd5829aae3b6..70403588da33 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/Android.bp
+++ b/packages/overlays/IconPackCircularAndroidOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackCircularAndroidOverlay",
theme: "IconPackCircularAndroid",
diff --git a/packages/overlays/IconPackCircularLauncherOverlay/Android.bp b/packages/overlays/IconPackCircularLauncherOverlay/Android.bp
index 5f2491d3cd66..4f8b6637a2b5 100644
--- a/packages/overlays/IconPackCircularLauncherOverlay/Android.bp
+++ b/packages/overlays/IconPackCircularLauncherOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackCircularLauncherOverlay",
theme: "IconPackCircularLauncher",
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/Android.bp b/packages/overlays/IconPackCircularSettingsOverlay/Android.bp
index d7bc6573e986..93220c87dcf9 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/Android.bp
+++ b/packages/overlays/IconPackCircularSettingsOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackCircularSettingsOverlay",
theme: "IconPackCircularSettings",
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/Android.bp b/packages/overlays/IconPackCircularSystemUIOverlay/Android.bp
index 73b8cd8e7d5f..4eaa4205fe96 100644
--- a/packages/overlays/IconPackCircularSystemUIOverlay/Android.bp
+++ b/packages/overlays/IconPackCircularSystemUIOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackCircularSystemUIOverlay",
theme: "IconPackCircularSystemUI",
diff --git a/packages/overlays/IconPackCircularThemePickerOverlay/Android.bp b/packages/overlays/IconPackCircularThemePickerOverlay/Android.bp
index 50639322607e..5105b7931922 100644
--- a/packages/overlays/IconPackCircularThemePickerOverlay/Android.bp
+++ b/packages/overlays/IconPackCircularThemePickerOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackCircularThemePickerOverlay",
theme: "IconPackCircularThemePicker",
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/Android.bp b/packages/overlays/IconPackFilledAndroidOverlay/Android.bp
index 83f365678caf..3c4025d6026c 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/Android.bp
+++ b/packages/overlays/IconPackFilledAndroidOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackFilledAndroidOverlay",
theme: "IconPackFilledAndroid",
diff --git a/packages/overlays/IconPackFilledLauncherOverlay/Android.bp b/packages/overlays/IconPackFilledLauncherOverlay/Android.bp
index 6ca256638a03..3c5078ce5933 100644
--- a/packages/overlays/IconPackFilledLauncherOverlay/Android.bp
+++ b/packages/overlays/IconPackFilledLauncherOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackFilledLauncherOverlay",
theme: "IconPackFilledLauncher",
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/Android.bp b/packages/overlays/IconPackFilledSettingsOverlay/Android.bp
index 8551bd54d588..b5148c23e053 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/Android.bp
+++ b/packages/overlays/IconPackFilledSettingsOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackFilledSettingsOverlay",
theme: "IconPackFilledSettings",
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/Android.bp b/packages/overlays/IconPackFilledSystemUIOverlay/Android.bp
index 684deb453d74..eb040a5a132d 100644
--- a/packages/overlays/IconPackFilledSystemUIOverlay/Android.bp
+++ b/packages/overlays/IconPackFilledSystemUIOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackFilledSystemUIOverlay",
theme: "IconPackFilledSystemUI",
diff --git a/packages/overlays/IconPackFilledThemePickerOverlay/Android.bp b/packages/overlays/IconPackFilledThemePickerOverlay/Android.bp
index dae378f67774..bee48089109b 100644
--- a/packages/overlays/IconPackFilledThemePickerOverlay/Android.bp
+++ b/packages/overlays/IconPackFilledThemePickerOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackFilledThemePickerOverlay",
theme: "IconPackFilledThemePicker",
diff --git a/packages/overlays/IconPackKaiAndroidOverlay/Android.bp b/packages/overlays/IconPackKaiAndroidOverlay/Android.bp
index 4161e252c312..ee588c1f1c55 100644
--- a/packages/overlays/IconPackKaiAndroidOverlay/Android.bp
+++ b/packages/overlays/IconPackKaiAndroidOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackKaiAndroidOverlay",
theme: "IconPackKaiAndroid",
diff --git a/packages/overlays/IconPackKaiLauncherOverlay/Android.bp b/packages/overlays/IconPackKaiLauncherOverlay/Android.bp
index 4bf8f11a8475..dcdad7aaed4e 100644
--- a/packages/overlays/IconPackKaiLauncherOverlay/Android.bp
+++ b/packages/overlays/IconPackKaiLauncherOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackKaiLauncherOverlay",
theme: "IconPackKaiLauncher",
diff --git a/packages/overlays/IconPackKaiSettingsOverlay/Android.bp b/packages/overlays/IconPackKaiSettingsOverlay/Android.bp
index c43f9e58a0c9..974bb540f4e7 100644
--- a/packages/overlays/IconPackKaiSettingsOverlay/Android.bp
+++ b/packages/overlays/IconPackKaiSettingsOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackKaiSettingsOverlay",
theme: "IconPackKaiSettings",
diff --git a/packages/overlays/IconPackKaiSystemUIOverlay/Android.bp b/packages/overlays/IconPackKaiSystemUIOverlay/Android.bp
index 22a8c2843956..b04ca6132c6d 100644
--- a/packages/overlays/IconPackKaiSystemUIOverlay/Android.bp
+++ b/packages/overlays/IconPackKaiSystemUIOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackKaiSystemUIOverlay",
theme: "IconPackKaiSystemUI",
diff --git a/packages/overlays/IconPackKaiThemePickerOverlay/Android.bp b/packages/overlays/IconPackKaiThemePickerOverlay/Android.bp
index 85eb1c46272f..875cd1d44d92 100644
--- a/packages/overlays/IconPackKaiThemePickerOverlay/Android.bp
+++ b/packages/overlays/IconPackKaiThemePickerOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackKaiThemePickerOverlay",
theme: "IconPackKaiThemePicker",
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/Android.bp b/packages/overlays/IconPackRoundedAndroidOverlay/Android.bp
index 948f015cabec..cb7b01361da3 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/Android.bp
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackRoundedAndroidOverlay",
theme: "IconPackRoundedAndroid",
diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/Android.bp b/packages/overlays/IconPackRoundedLauncherOverlay/Android.bp
index 5fbe6352f889..8ab6d957720e 100644
--- a/packages/overlays/IconPackRoundedLauncherOverlay/Android.bp
+++ b/packages/overlays/IconPackRoundedLauncherOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackRoundedLauncherOverlay",
theme: "IconPackRoundedLauncher",
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/Android.bp b/packages/overlays/IconPackRoundedSettingsOverlay/Android.bp
index b1a07137eaa2..ee2f98a96864 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/Android.bp
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackRoundedSettingsOverlay",
theme: "IconPackRoundedSettings",
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/Android.bp b/packages/overlays/IconPackRoundedSystemUIOverlay/Android.bp
index 643299898169..ee0220a44943 100644
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/Android.bp
+++ b/packages/overlays/IconPackRoundedSystemUIOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackRoundedSystemUIOverlay",
theme: "IconPackRoundedSystemUI",
diff --git a/packages/overlays/IconPackRoundedThemePickerOverlay/Android.bp b/packages/overlays/IconPackRoundedThemePickerOverlay/Android.bp
index 95e1d3a2ac6c..d74765c33607 100644
--- a/packages/overlays/IconPackRoundedThemePickerOverlay/Android.bp
+++ b/packages/overlays/IconPackRoundedThemePickerOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackRoundedThemePickerOverlay",
theme: "IconPackRoundedTheme",
diff --git a/packages/overlays/IconPackSamAndroidOverlay/Android.bp b/packages/overlays/IconPackSamAndroidOverlay/Android.bp
index e8c33b10fb9e..2e9dc3472674 100644
--- a/packages/overlays/IconPackSamAndroidOverlay/Android.bp
+++ b/packages/overlays/IconPackSamAndroidOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackSamAndroidOverlay",
theme: "IconPackSamAndroid",
diff --git a/packages/overlays/IconPackSamLauncherOverlay/Android.bp b/packages/overlays/IconPackSamLauncherOverlay/Android.bp
index a46964665862..aa0cf0077ab9 100644
--- a/packages/overlays/IconPackSamLauncherOverlay/Android.bp
+++ b/packages/overlays/IconPackSamLauncherOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackSamLauncherOverlay",
theme: "IconPackSamLauncher",
diff --git a/packages/overlays/IconPackSamSettingsOverlay/Android.bp b/packages/overlays/IconPackSamSettingsOverlay/Android.bp
index bc1fa458ad9a..a62037f3d5c2 100644
--- a/packages/overlays/IconPackSamSettingsOverlay/Android.bp
+++ b/packages/overlays/IconPackSamSettingsOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackSamSettingsOverlay",
theme: "IconPackSamSettings",
diff --git a/packages/overlays/IconPackSamSystemUIOverlay/Android.bp b/packages/overlays/IconPackSamSystemUIOverlay/Android.bp
index db77352f42b9..96ba7a096e6a 100644
--- a/packages/overlays/IconPackSamSystemUIOverlay/Android.bp
+++ b/packages/overlays/IconPackSamSystemUIOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackSamSystemUIOverlay",
theme: "IconPackSamSystemUI",
diff --git a/packages/overlays/IconPackSamThemePickerOverlay/Android.bp b/packages/overlays/IconPackSamThemePickerOverlay/Android.bp
index c216868a2a5e..7376f03a2c7f 100644
--- a/packages/overlays/IconPackSamThemePickerOverlay/Android.bp
+++ b/packages/overlays/IconPackSamThemePickerOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackSamThemePickerOverlay",
theme: "IconPackSamThemePicker",
diff --git a/packages/overlays/IconPackVictorAndroidOverlay/Android.bp b/packages/overlays/IconPackVictorAndroidOverlay/Android.bp
index de62af1c6287..ee7377863287 100644
--- a/packages/overlays/IconPackVictorAndroidOverlay/Android.bp
+++ b/packages/overlays/IconPackVictorAndroidOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackVictorAndroidOverlay",
theme: "IconPackVictorAndroid",
diff --git a/packages/overlays/IconPackVictorLauncherOverlay/Android.bp b/packages/overlays/IconPackVictorLauncherOverlay/Android.bp
index fc4c3606de8e..a0cd45a81e20 100644
--- a/packages/overlays/IconPackVictorLauncherOverlay/Android.bp
+++ b/packages/overlays/IconPackVictorLauncherOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackVictorLauncherOverlay",
theme: "IconPackVictorLauncher",
diff --git a/packages/overlays/IconPackVictorSettingsOverlay/Android.bp b/packages/overlays/IconPackVictorSettingsOverlay/Android.bp
index 046bb3d25a12..7807c6bcccc8 100644
--- a/packages/overlays/IconPackVictorSettingsOverlay/Android.bp
+++ b/packages/overlays/IconPackVictorSettingsOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackVictorSettingsOverlay",
theme: "IconPackVictorSettings",
diff --git a/packages/overlays/IconPackVictorSystemUIOverlay/Android.bp b/packages/overlays/IconPackVictorSystemUIOverlay/Android.bp
index b8a9e77ebf7d..2deb6cd73ba1 100644
--- a/packages/overlays/IconPackVictorSystemUIOverlay/Android.bp
+++ b/packages/overlays/IconPackVictorSystemUIOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackVictorSystemUIOverlay",
theme: "IconPackVictorSystemUI",
diff --git a/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp b/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp
index 6f0144e9e351..a18ebb3eaea5 100644
--- a/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp
+++ b/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconPackVictorThemePickerOverlay",
theme: "IconPackVictorThemePicker",
diff --git a/packages/overlays/IconShapeHeartOverlay/Android.bp b/packages/overlays/IconShapeHeartOverlay/Android.bp
index ec55712f2309..1da8f4ff7fb3 100644
--- a/packages/overlays/IconShapeHeartOverlay/Android.bp
+++ b/packages/overlays/IconShapeHeartOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconShapeHeartOverlay",
theme: "IconShapeHeart",
diff --git a/packages/overlays/IconShapePebbleOverlay/Android.bp b/packages/overlays/IconShapePebbleOverlay/Android.bp
index 7dc4fde140c8..fa2a5bb825f3 100644
--- a/packages/overlays/IconShapePebbleOverlay/Android.bp
+++ b/packages/overlays/IconShapePebbleOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconShapePebbleOverlay",
theme: "IconShapePebble",
diff --git a/packages/overlays/IconShapeRoundedRectOverlay/Android.bp b/packages/overlays/IconShapeRoundedRectOverlay/Android.bp
index b8b85314a211..5052d08f1edf 100644
--- a/packages/overlays/IconShapeRoundedRectOverlay/Android.bp
+++ b/packages/overlays/IconShapeRoundedRectOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconShapeRoundedRectOverlay",
theme: "IconShapeRoundedRect",
diff --git a/packages/overlays/IconShapeSquareOverlay/Android.bp b/packages/overlays/IconShapeSquareOverlay/Android.bp
index fdeffeee25d2..1176abddd71f 100644
--- a/packages/overlays/IconShapeSquareOverlay/Android.bp
+++ b/packages/overlays/IconShapeSquareOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconShapeSquareOverlay",
theme: "IconShapeSquare",
diff --git a/packages/overlays/IconShapeSquircleOverlay/Android.bp b/packages/overlays/IconShapeSquircleOverlay/Android.bp
index 468f0f7ee2c7..8c219f340040 100644
--- a/packages/overlays/IconShapeSquircleOverlay/Android.bp
+++ b/packages/overlays/IconShapeSquircleOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconShapeSquircleOverlay",
theme: "IconShapeSquircle",
diff --git a/packages/overlays/IconShapeTaperedRectOverlay/Android.bp b/packages/overlays/IconShapeTaperedRectOverlay/Android.bp
index 1e48cd154317..78855e8daba2 100644
--- a/packages/overlays/IconShapeTaperedRectOverlay/Android.bp
+++ b/packages/overlays/IconShapeTaperedRectOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconShapeTaperedRectOverlay",
theme: "IconShapeTaperedRect",
diff --git a/packages/overlays/IconShapeTeardropOverlay/Android.bp b/packages/overlays/IconShapeTeardropOverlay/Android.bp
index 017d58ec4e77..dd36f4ffc995 100644
--- a/packages/overlays/IconShapeTeardropOverlay/Android.bp
+++ b/packages/overlays/IconShapeTeardropOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconShapeTeardropOverlay",
theme: "IconShapeTeardrop",
diff --git a/packages/overlays/IconShapeVesselOverlay/Android.bp b/packages/overlays/IconShapeVesselOverlay/Android.bp
index ba3b30954e7f..2e7f8bc6cf66 100644
--- a/packages/overlays/IconShapeVesselOverlay/Android.bp
+++ b/packages/overlays/IconShapeVesselOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "IconShapeVesselOverlay",
theme: "IconShapeVessel",
diff --git a/packages/overlays/NavigationBarMode2ButtonOverlay/Android.bp b/packages/overlays/NavigationBarMode2ButtonOverlay/Android.bp
index e4fcce15250f..35f671bab875 100644
--- a/packages/overlays/NavigationBarMode2ButtonOverlay/Android.bp
+++ b/packages/overlays/NavigationBarMode2ButtonOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "NavigationBarMode2ButtonOverlay",
theme: "NavigationBarMode2Button",
diff --git a/packages/overlays/NavigationBarMode3ButtonOverlay/Android.bp b/packages/overlays/NavigationBarMode3ButtonOverlay/Android.bp
index 9b6c9988b9bb..fe9cc81f0d52 100644
--- a/packages/overlays/NavigationBarMode3ButtonOverlay/Android.bp
+++ b/packages/overlays/NavigationBarMode3ButtonOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "NavigationBarMode3ButtonOverlay",
theme: "NavigationBarMode3Button",
diff --git a/packages/overlays/NavigationBarModeGesturalOverlay/Android.bp b/packages/overlays/NavigationBarModeGesturalOverlay/Android.bp
index ba290459a279..791f4205481f 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlay/Android.bp
+++ b/packages/overlays/NavigationBarModeGesturalOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "NavigationBarModeGesturalOverlay",
theme: "NavigationBarModeGestural",
diff --git a/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/Android.bp b/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/Android.bp
index 0c688a988533..28f9f3341307 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/Android.bp
+++ b/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "NavigationBarModeGesturalOverlayExtraWideBack",
theme: "NavigationBarModeGesturalExtraWideBack",
diff --git a/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/Android.bp b/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/Android.bp
index 85d514f7fbac..f8a56030e0e4 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/Android.bp
+++ b/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "NavigationBarModeGesturalOverlayNarrowBack",
theme: "NavigationBarModeGesturalNarrowBack",
diff --git a/packages/overlays/NavigationBarModeGesturalOverlayWideBack/Android.bp b/packages/overlays/NavigationBarModeGesturalOverlayWideBack/Android.bp
index 84be626eefec..60ee6d540dc8 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlayWideBack/Android.bp
+++ b/packages/overlays/NavigationBarModeGesturalOverlayWideBack/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "NavigationBarModeGesturalOverlayWideBack",
theme: "NavigationBarModeGesturalWideBack",
diff --git a/packages/overlays/OneHandedModeGesturalOverlay/Android.bp b/packages/overlays/OneHandedModeGesturalOverlay/Android.bp
index 9c9d0ef380a7..468069dd8334 100644
--- a/packages/overlays/OneHandedModeGesturalOverlay/Android.bp
+++ b/packages/overlays/OneHandedModeGesturalOverlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
runtime_resource_overlay {
name: "OneHandedModeGesturalOverlay",
theme: "OneHandedModeGestural",
diff --git a/packages/services/CameraExtensionsProxy/Android.bp b/packages/services/CameraExtensionsProxy/Android.bp
index e2e4af2a35f4..ea0703e2bc24 100644
--- a/packages/services/CameraExtensionsProxy/Android.bp
+++ b/packages/services/CameraExtensionsProxy/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_app {
name: "CameraExtensionsProxy",
srcs: ["src/**/*.java"],
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ea1473ea3db7..c63c2e1a257d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -777,6 +777,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
// performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
+
+ if (Binder.getCallingPid() == OWN_PROCESS_ID) {
+ return new ArrayList<>(getUserStateLocked(resolvedUserId).mInstalledServices);
+ }
return getUserStateLocked(resolvedUserId).mInstalledServices;
}
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 809304bb24ae..7518c7a8bdc9 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -2673,7 +2673,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
info.widgetFeatures = sa.getInt(
com.android.internal.R.styleable.AppWidgetProviderInfo_widgetFeatures, 0);
- info.descriptionResource = sa.getResourceId(
+ info.descriptionRes = sa.getResourceId(
com.android.internal.R.styleable.AppWidgetProviderInfo_description,
Resources.ID_NULL);
sa.recycle();
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 6c30999f63a4..38275f7cd348 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1245,10 +1245,9 @@ public class BackupManagerService extends IBackupManager.Stub {
@Override
public IRestoreSession beginRestoreSessionForUser(
- int userId, String packageName, String transportID,
- @OperationType int operationType) throws RemoteException {
+ int userId, String packageName, String transportID) throws RemoteException {
return isUserReadyForBackup(userId)
- ? beginRestoreSession(userId, packageName, transportID, operationType) : null;
+ ? beginRestoreSession(userId, packageName, transportID) : null;
}
/**
@@ -1257,15 +1256,13 @@ public class BackupManagerService extends IBackupManager.Stub {
*/
@Nullable
public IRestoreSession beginRestoreSession(
- @UserIdInt int userId, String packageName, String transportName,
- @OperationType int operationType) {
+ @UserIdInt int userId, String packageName, String transportName) {
UserBackupManagerService userBackupManagerService =
getServiceForUserIfCallerHasPermission(userId, "beginRestoreSession()");
return userBackupManagerService == null
? null
- : userBackupManagerService.beginRestoreSession(packageName, transportName,
- operationType);
+ : userBackupManagerService.beginRestoreSession(packageName, transportName);
}
@Override
@@ -1350,15 +1347,15 @@ public class BackupManagerService extends IBackupManager.Stub {
if (!isUserReadyForBackup(userId)) {
return BackupManager.ERROR_BACKUP_NOT_ALLOWED;
}
- return requestBackup(userId, packages, observer, monitor, flags, OperationType.BACKUP);
+ return requestBackup(userId, packages, observer, monitor, flags);
}
@Override
public int requestBackup(String[] packages, IBackupObserver observer,
- IBackupManagerMonitor monitor, int flags, @OperationType int operationType)
+ IBackupManagerMonitor monitor, int flags)
throws RemoteException {
return requestBackup(binderGetCallingUserId(), packages,
- observer, monitor, flags, operationType);
+ observer, monitor, flags);
}
/**
@@ -1370,15 +1367,13 @@ public class BackupManagerService extends IBackupManager.Stub {
String[] packages,
IBackupObserver observer,
IBackupManagerMonitor monitor,
- int flags,
- @OperationType int operationType) {
+ int flags) {
UserBackupManagerService userBackupManagerService =
getServiceForUserIfCallerHasPermission(userId, "requestBackup()");
return userBackupManagerService == null
? BackupManager.ERROR_BACKUP_NOT_ALLOWED
- : userBackupManagerService.requestBackup(packages, observer, monitor, flags,
- operationType);
+ : userBackupManagerService.requestBackup(packages, observer, monitor, flags);
}
@Override
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 136cd22fad83..9ee0159e903a 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -96,6 +96,7 @@ import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.EventLog;
+import android.util.FeatureFlagUtils;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -127,6 +128,7 @@ import com.android.server.backup.params.RestoreParams;
import com.android.server.backup.restore.ActiveRestoreSession;
import com.android.server.backup.restore.PerformUnifiedRestoreTask;
import com.android.server.backup.transport.TransportClient;
+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;
@@ -1860,19 +1862,10 @@ public class UserBackupManagerService {
/**
* Requests a backup for the inputted {@code packages} with a specified {@link
- * IBackupManagerMonitor}.
- */
- public int requestBackup(String[] packages, IBackupObserver observer,
- IBackupManagerMonitor monitor, int flags) {
- return requestBackup(packages, observer, monitor, flags, OperationType.BACKUP);
- }
-
- /**
- * Requests a backup for the inputted {@code packages} with a specified {@link
* IBackupManagerMonitor} and {@link OperationType}.
*/
public int requestBackup(String[] packages, IBackupObserver observer,
- IBackupManagerMonitor monitor, int flags, @OperationType int operationType) {
+ IBackupManagerMonitor monitor, int flags) {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup");
if (packages == null || packages.length < 1) {
@@ -1903,13 +1896,16 @@ public class UserBackupManagerService {
final TransportClient transportClient;
final String transportDirName;
+ int operationType;
try {
transportDirName =
mTransportManager.getTransportDirName(
mTransportManager.getCurrentTransportName());
transportClient =
mTransportManager.getCurrentTransportClientOrThrow("BMS.requestBackup()");
- } catch (TransportNotRegisteredException e) {
+ operationType = getOperationTypeFromTransport(transportClient);
+ } catch (TransportNotRegisteredException | TransportNotAvailableException
+ | RemoteException e) {
BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
monitor = BackupManagerMonitorUtils.monitorEvent(monitor,
BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL,
@@ -4024,15 +4020,13 @@ public class UserBackupManagerService {
}
/** Hand off a restore session. */
- public IRestoreSession beginRestoreSession(String packageName, String transport,
- @OperationType int operationType) {
+ public IRestoreSession beginRestoreSession(String packageName, String transport) {
if (DEBUG) {
Slog.v(
TAG,
addUserIdToLogMessage(
mUserId,
- "beginRestoreSession: pkg=" + packageName + " transport=" + transport
- + "operationType=" + operationType));
+ "beginRestoreSession: pkg=" + packageName + " transport=" + transport));
}
boolean needPermission = true;
@@ -4073,6 +4067,17 @@ public class UserBackupManagerService {
}
}
+ int operationType;
+ try {
+ operationType = getOperationTypeFromTransport(
+ mTransportManager.getTransportClientOrThrow(transport, /* caller */
+ "BMS.beginRestoreSession"));
+ } catch (TransportNotAvailableException | TransportNotRegisteredException
+ | RemoteException e) {
+ Slog.w(TAG, "Failed to get operation type from transport: " + e);
+ return null;
+ }
+
synchronized (this) {
if (mActiveRestoreSession != null) {
Slog.i(
@@ -4356,6 +4361,34 @@ public class UserBackupManagerService {
}
}
+ @VisibleForTesting
+ @OperationType int getOperationTypeFromTransport(TransportClient transportClient)
+ throws TransportNotAvailableException, RemoteException {
+ if (!shouldUseNewBackupEligibilityRules()) {
+ // Return the default to stick to the legacy behaviour.
+ return OperationType.BACKUP;
+ }
+
+ long oldCallingId = Binder.clearCallingIdentity();
+ try {
+ IBackupTransport transport = transportClient.connectOrThrow(
+ /* caller */ "BMS.getOperationTypeFromTransport");
+ if ((transport.getTransportFlags() & BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER) != 0) {
+ return OperationType.MIGRATION;
+ } else {
+ return OperationType.BACKUP;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(oldCallingId);
+ }
+ }
+
+ @VisibleForTesting
+ boolean shouldUseNewBackupEligibilityRules() {
+ return FeatureFlagUtils.isEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES);
+ }
+
private static String addUserIdToLogMessage(int userId, String message) {
return "[UserID:" + userId + "] " + message;
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 76c8d3001158..ebfa9171b2b9 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -142,18 +142,13 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
-//TODO onStop schedule unbind in 5 seconds
-//TODO make sure APIs are only callable from currently focused app
-//TODO schedule stopScan on activity destroy(except if configuration change)
-//TODO on associate called again after configuration change -> replace old callback with new
-//TODO avoid leaking calling activity in IFindDeviceCallback (see PrintManager#print for example)
/** @hide */
@SuppressLint("LongLogTag")
public class CompanionDeviceManagerService extends SystemService implements Binder.DeathRecipient {
private static final ComponentName SERVICE_TO_BIND_TO = ComponentName.createRelative(
CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME,
- ".DeviceDiscoveryService");
+ ".CompanionDeviceDiscoveryService");
private static final long DEVICE_DISAPPEARED_TIMEOUT_MS = 10 * 1000;
private static final long DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS = 10 * 60 * 1000;
@@ -1422,7 +1417,9 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
@Override
- public void onDeviceDisconnected(BluetoothDevice device) {
+ public void onDeviceDisconnected(BluetoothDevice device, @DisconnectReason int reason) {
+ Slog.d(LOG_TAG, device.getAddress() + " disconnected w/ reason: (" + reason + ") "
+ + BluetoothAdapter.BluetoothConnectionCallback.disconnectReasonText(reason));
CompanionDeviceManagerService.this.onDeviceDisconnected(device.getAddress());
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 9d86f4eaa520..f4138d10a84d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -188,14 +188,16 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.BitUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.LocationPermissionChecker;
import com.android.internal.util.MessageUtils;
import com.android.modules.utils.BasicShellCommandHandler;
+import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult;
import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
+import com.android.net.module.util.PermissionUtils;
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.AutodestructReference;
import com.android.server.connectivity.DataConnectionStats;
@@ -1510,7 +1512,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
return getActiveNetworkForUidInternal(uid, ignoreBlocked);
}
@@ -1533,7 +1535,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
final NetworkState state = getUnfilteredActiveNetworkState(uid);
filterNetworkStateForUid(state, uid, ignoreBlocked);
return state.networkInfo;
@@ -1877,7 +1879,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public NetworkState[] getAllNetworkState() {
// This contains IMSI details, so make sure the caller is privileged.
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
final ArrayList<NetworkState> result = new ArrayList<>();
for (Network network : getAllNetworks()) {
@@ -2301,7 +2303,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Public because it's used by mLockdownTracker.
public void sendConnectedBroadcast(NetworkInfo info) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
}
@@ -2565,13 +2567,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (!checkDumpPermission(mContext, TAG, pw)) return;
if (asProto) return;
- if (ArrayUtils.contains(args, DIAG_ARG)) {
+ if (CollectionUtils.contains(args, DIAG_ARG)) {
dumpNetworkDiagnostics(pw);
return;
- } else if (ArrayUtils.contains(args, NETWORK_ARG)) {
+ } else if (CollectionUtils.contains(args, NETWORK_ARG)) {
dumpNetworks(pw);
return;
- } else if (ArrayUtils.contains(args, REQUEST_ARG)) {
+ } else if (CollectionUtils.contains(args, REQUEST_ARG)) {
dumpNetworkRequests(pw);
return;
}
@@ -2642,7 +2644,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
pw.println();
- if (ArrayUtils.contains(args, SHORT_ARG) == false) {
+ if (!CollectionUtils.contains(args, SHORT_ARG)) {
pw.println();
pw.println("mNetworkRequestInfoLogs (most recent first):");
pw.increaseIndent();
@@ -4684,7 +4686,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public void setGlobalProxy(final ProxyInfo proxyProperties) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
mProxyTracker.setGlobalProxy(proxyProperties);
}
@@ -4809,7 +4811,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- if (ArrayUtils.isEmpty(underlyingNetworks)) return null;
+ if (CollectionUtils.isEmpty(underlyingNetworks)) return null;
List<String> interfaces = new ArrayList<>();
for (Network network : underlyingNetworks) {
@@ -4853,7 +4855,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (!nai.supportsUnderlyingNetworks()) return false;
final Network[] underlying = underlyingNetworksOrDefault(
nai.networkCapabilities.getOwnerUid(), nai.declaredUnderlyingNetworks);
- return ArrayUtils.contains(underlying, network);
+ return CollectionUtils.contains(underlying, network);
}
/**
@@ -4886,7 +4888,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public void setRequireVpnForUids(boolean requireVpn, UidRange[] ranges) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_REQUIRE_VPN_FOR_UIDS,
encodeBool(requireVpn), 0 /* arg2 */, ranges));
}
@@ -5317,8 +5319,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
}
- // TODO: use NetworkStackUtils.convertToIntArray after moving it
- return ArrayUtils.convertToIntArray(new ArrayList<>(thresholds));
+ return CollectionUtils.toIntArray(new ArrayList<>(thresholds));
}
private void updateSignalStrengthThresholds(
@@ -6437,7 +6438,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
@NonNull NetworkCapabilities agentCaps, @NonNull NetworkCapabilities newNc) {
underlyingNetworks = underlyingNetworksOrDefault(
agentCaps.getOwnerUid(), underlyingNetworks);
- int[] transportTypes = agentCaps.getTransportTypes();
+ long transportTypes = BitUtils.packBits(agentCaps.getTransportTypes());
int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
// metered if any underlying is metered, or originally declared metered by the agent.
@@ -6456,7 +6457,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
final NetworkCapabilities underlyingCaps = underlying.networkCapabilities;
hadUnderlyingNetworks = true;
for (int underlyingType : underlyingCaps.getTransportTypes()) {
- transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
+ transportTypes |= 1L << underlyingType;
}
// Merge capabilities of this underlying network. For bandwidth, assume the
@@ -6487,7 +6488,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
suspended = false;
}
- newNc.setTransportTypes(transportTypes);
+ newNc.setTransportTypes(BitUtils.unpackBits(transportTypes));
newNc.setLinkDownstreamBandwidthKbps(downKbps);
newNc.setLinkUpstreamBandwidthKbps(upKbps);
newNc.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
@@ -8552,14 +8553,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
for (NetworkAgentInfo virtual : mNetworkAgentInfos) {
if (virtual.supportsUnderlyingNetworks()
&& virtual.networkCapabilities.getOwnerUid() == callbackUid
- && ArrayUtils.contains(virtual.declaredUnderlyingNetworks, nai.network)) {
+ && CollectionUtils.contains(virtual.declaredUnderlyingNetworks, nai.network)) {
return true;
}
}
// Administrator UIDs also contains the Owner UID
final int[] administratorUids = nai.networkCapabilities.getAdministratorUids();
- return ArrayUtils.contains(administratorUids, callbackUid);
+ return CollectionUtils.contains(administratorUids, callbackUid);
}
@Override
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 88ce2208adcb..e29e894a5cc0 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -28,6 +28,7 @@ import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.image.IDynamicSystemService;
+import android.os.storage.DiskInfo;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.util.Slog;
@@ -40,6 +41,7 @@ import java.io.File;
*/
public class DynamicSystemService extends IDynamicSystemService.Stub {
private static final String TAG = "DynamicSystemService";
+ private static final long MINIMUM_SD_MB = (30L << 10);
private static final int GSID_ROUGH_TIMEOUT_MS = 8192;
private static final String PATH_DEFAULT = "/data/gsi/";
private Context mContext;
@@ -95,6 +97,13 @@ public class DynamicSystemService extends IDynamicSystemService.Stub {
if (!volume.isMountedWritable()) {
continue;
}
+ DiskInfo disk = volume.getDisk();
+ long mega = disk.size >> 20;
+ Slog.i(TAG, volume.getPath() + ": " + mega + " MB");
+ if (mega < MINIMUM_SD_MB) {
+ Slog.i(TAG, volume.getPath() + ": insufficient storage");
+ continue;
+ }
File sd_internal = volume.getInternalPathForUser(userId);
if (sd_internal != null) {
path = new File(sd_internal, dsuSlot).getPath();
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index b48bc900aa84..81d4b9da63c8 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -48,7 +48,6 @@ import android.net.TrafficStats;
import android.net.util.NetdService;
import android.os.Binder;
import android.os.IBinder;
-import android.os.INetworkManagementService;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
@@ -64,6 +63,7 @@ import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
+import com.android.net.module.util.NetdUtils;
import libcore.io.IoUtils;
@@ -117,9 +117,6 @@ public class IpSecService extends IIpSecService.Stub {
/* Binder context for this service */
private final Context mContext;
- /* NetworkManager instance */
- private final INetworkManagementService mNetworkManager;
-
/**
* The next non-repeating global ID for tracking resources between users, this service, and
* kernel data structures. Accessing this variable is not thread safe, so it is only read or
@@ -1014,13 +1011,13 @@ public class IpSecService extends IIpSecService.Stub {
*
* @param context Binder context for this service
*/
- private IpSecService(Context context, INetworkManagementService networkManager) {
- this(context, networkManager, IpSecServiceConfiguration.GETSRVINSTANCE);
+ private IpSecService(Context context) {
+ this(context, IpSecServiceConfiguration.GETSRVINSTANCE);
}
- static IpSecService create(Context context, INetworkManagementService networkManager)
+ static IpSecService create(Context context)
throws InterruptedException {
- final IpSecService service = new IpSecService(context, networkManager);
+ final IpSecService service = new IpSecService(context);
service.connectNativeNetdService();
return service;
}
@@ -1034,11 +1031,9 @@ public class IpSecService extends IIpSecService.Stub {
/** @hide */
@VisibleForTesting
- public IpSecService(Context context, INetworkManagementService networkManager,
- IpSecServiceConfiguration config) {
+ public IpSecService(Context context, IpSecServiceConfiguration config) {
this(
context,
- networkManager,
config,
(fd, uid) -> {
try {
@@ -1052,10 +1047,9 @@ public class IpSecService extends IIpSecService.Stub {
/** @hide */
@VisibleForTesting
- public IpSecService(Context context, INetworkManagementService networkManager,
- IpSecServiceConfiguration config, UidFdTagger uidFdTagger) {
+ public IpSecService(Context context, IpSecServiceConfiguration config,
+ UidFdTagger uidFdTagger) {
mContext = context;
- mNetworkManager = Objects.requireNonNull(networkManager);
mSrvConfig = config;
mUidFdTagger = uidFdTagger;
}
@@ -1335,7 +1329,7 @@ public class IpSecService extends IIpSecService.Stub {
netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId);
Binder.withCleanCallingIdentity(() -> {
- mNetworkManager.setInterfaceUp(intfName);
+ NetdUtils.setInterfaceUp(netd, intfName);
});
for (int selAddrFamily : ADDRESS_FAMILIES) {
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 329ab9983c90..8d5d3d939e4b 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
@@ -837,7 +839,10 @@ public class VcnManagementService extends IVcnManagementService.Stub {
// Notify all registered StatusCallbacks for this subGroup
for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
if (isCallbackPermissioned(cbInfo)) {
- Binder.withCleanCallingIdentity(() -> cbInfo.mCallback.onEnteredSafeMode());
+ Binder.withCleanCallingIdentity(
+ () ->
+ cbInfo.mCallback.onVcnStatusChanged(
+ VCN_STATUS_CODE_SAFE_MODE));
}
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 5550999b2405..2efc83c4af06 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -52,6 +52,7 @@ import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
+import android.app.ForegroundServiceStartNotAllowedException;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
import android.app.Notification;
@@ -693,7 +694,7 @@ public final class ActiveServices {
+ "could not resolve client package " + callingPackage);
}
if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, aInfo.uid)) {
- throw new IllegalStateException(msg);
+ throw new ForegroundServiceStartNotAllowedException(msg);
}
return null;
}
@@ -1778,7 +1779,7 @@ public final class ActiveServices {
ignoreForeground = true;
if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID,
r.appInfo.uid)) {
- throw new IllegalStateException(msg);
+ throw new ForegroundServiceStartNotAllowedException(msg);
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5ee0e040019c..33c0f9d628dc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -142,6 +142,8 @@ import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityClient;
import android.app.ActivityManager;
+import android.app.ActivityManager.PendingIntentInfo;
+import android.app.ActivityManager.ProcessCapability;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager.RootTaskInfo;
@@ -173,6 +175,7 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.ProcessMemoryState;
import android.app.ProfilerInfo;
+import android.app.PropertyInvalidatedCache;
import android.app.WaitResult;
import android.app.backup.BackupManager.OperationType;
import android.app.backup.IBackupManager;
@@ -181,7 +184,6 @@ import android.app.usage.UsageEvents.Event;
import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
-import android.compat.Compatibility;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
@@ -306,7 +308,6 @@ import com.android.internal.app.IAppOpsService;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.SystemUserHomeActivity;
import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.content.PackageHelper;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
@@ -4859,19 +4860,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public String getPackageForIntentSender(IIntentSender pendingResult) {
- if (!(pendingResult instanceof PendingIntentRecord)) {
- return null;
- }
- try {
- PendingIntentRecord res = (PendingIntentRecord)pendingResult;
- return res.key.packageName;
- } catch (ClassCastException e) {
- }
- return null;
- }
-
- @Override
public void registerIntentSenderCancelListener(IIntentSender sender, IResultReceiver receiver) {
mPendingIntentController.registerIntentSenderCancelListener(sender, receiver);
}
@@ -4883,15 +4871,17 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public int getUidForIntentSender(IIntentSender sender) {
+ public PendingIntentInfo getInfoForIntentSender(IIntentSender sender) {
if (sender instanceof PendingIntentRecord) {
- try {
- PendingIntentRecord res = (PendingIntentRecord)sender;
- return res.uid;
- } catch (ClassCastException e) {
- }
+ PendingIntentRecord res = (PendingIntentRecord) sender;
+ return new PendingIntentInfo(
+ res.key.packageName,
+ res.uid,
+ (res.key.flags & PendingIntent.FLAG_IMMUTABLE) != 0,
+ res.key.type);
+ } else {
+ throw new IllegalArgumentException();
}
- return -1;
}
@Override
@@ -4917,15 +4907,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public boolean isIntentSenderImmutable(IIntentSender pendingResult) {
- if (pendingResult instanceof PendingIntentRecord) {
- final PendingIntentRecord res = (PendingIntentRecord) pendingResult;
- return (res.key.flags & PendingIntent.FLAG_IMMUTABLE) != 0;
- }
- return false;
- }
-
- @Override
public boolean isIntentSenderAnActivity(IIntentSender pendingResult) {
if (!(pendingResult instanceof PendingIntentRecord)) {
return false;
@@ -4942,33 +4923,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public boolean isIntentSenderAForegroundService(IIntentSender pendingResult) {
- if (pendingResult instanceof PendingIntentRecord) {
- final PendingIntentRecord res = (PendingIntentRecord) pendingResult;
- return res.key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE;
- }
- return false;
- }
-
- @Override
- public boolean isIntentSenderAService(IIntentSender pendingResult) {
- if (pendingResult instanceof PendingIntentRecord) {
- final PendingIntentRecord res = (PendingIntentRecord) pendingResult;
- return res.key.type == ActivityManager.INTENT_SENDER_SERVICE;
- }
- return false;
- }
-
- @Override
- public boolean isIntentSenderABroadcast(IIntentSender pendingResult) {
- if (pendingResult instanceof PendingIntentRecord) {
- final PendingIntentRecord res = (PendingIntentRecord) pendingResult;
- return res.key.type == ActivityManager.INTENT_SENDER_BROADCAST;
- }
- return false;
- }
-
- @Override
public Intent getIntentForIntentSender(IIntentSender pendingResult) {
enforceCallingPermission(Manifest.permission.GET_INTENT_SENDER_INTENT,
"getIntentForIntentSender()");
@@ -6083,10 +6037,18 @@ public class ActivityManagerService extends IActivityManager.Stub
abiOverride, zygotePolicyFlags);
}
- // TODO: Move to ProcessList?
@GuardedBy("this")
final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
boolean disableHiddenApiChecks, String abiOverride, int zygotePolicyFlags) {
+ return addAppLocked(info, customProcess, isolated, disableHiddenApiChecks,
+ false /* disableTestApiChecks */, abiOverride, zygotePolicyFlags);
+ }
+
+ // TODO: Move to ProcessList?
+ @GuardedBy("this")
+ final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
+ boolean disableHiddenApiChecks, boolean disableTestApiChecks,
+ String abiOverride, int zygotePolicyFlags) {
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
@@ -6121,7 +6083,8 @@ public class ActivityManagerService extends IActivityManager.Stub
mPersistentStartingProcesses.add(app);
mProcessList.startProcessLocked(app, new HostingRecord("added application",
customProcess != null ? customProcess : app.processName),
- zygotePolicyFlags, disableHiddenApiChecks, abiOverride);
+ zygotePolicyFlags, disableHiddenApiChecks, disableTestApiChecks,
+ abiOverride);
}
return app;
@@ -6624,6 +6587,18 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
+ public @ProcessCapability int getUidProcessCapabilities(int uid, String callingPackage) {
+ if (!hasUsageStatsPermission(callingPackage)) {
+ enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+ "getUidProcessState");
+ }
+
+ synchronized (mProcLock) {
+ return mProcessList.getUidProcessCapabilityLOSP(uid);
+ }
+ }
+
+ @Override
public void registerUidObserver(IUidObserver observer, int which, int cutpoint,
String callingPackage) {
if (!hasUsageStatsPermission(callingPackage)) {
@@ -9863,6 +9838,10 @@ public class ActivityManagerService extends IActivityManager.Stub
if (thread != null) {
pw.println("\n\n** Cache info for pid " + pid + " [" + r.processName + "] **");
pw.flush();
+ if (pid == MY_PID) {
+ PropertyInvalidatedCache.dumpCacheInfo(fd, args);
+ continue;
+ }
try {
TransferPipe tp = new TransferPipe();
try {
@@ -10065,6 +10044,7 @@ public class ActivityManagerService extends IActivityManager.Stub
ProcessList.PERSISTENT_SERVICE_ADJ, ProcessList.FOREGROUND_APP_ADJ,
ProcessList.VISIBLE_APP_ADJ,
ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_LOW_APP_ADJ,
+ ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ,
ProcessList.BACKUP_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ,
ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.CACHED_APP_MIN_ADJ
@@ -10072,7 +10052,7 @@ public class ActivityManagerService extends IActivityManager.Stub
static final String[] DUMP_MEM_OOM_LABEL = new String[] {
"Native",
"System", "Persistent", "Persistent Service", "Foreground",
- "Visible", "Perceptible", "Perceptible Low",
+ "Visible", "Perceptible", "Perceptible Low", "Perceptible Medium",
"Heavy Weight", "Backup",
"A Services", "Home",
"Previous", "B Services", "Cached"
@@ -10080,7 +10060,7 @@ public class ActivityManagerService extends IActivityManager.Stub
static final String[] DUMP_MEM_OOM_COMPACT_LABEL = new String[] {
"native",
"sys", "pers", "persvc", "fore",
- "vis", "percept", "perceptl",
+ "vis", "percept", "perceptl", "perceptm",
"heavy", "backup",
"servicea", "home",
"prev", "serviceb", "cached"
@@ -13557,8 +13537,6 @@ public class ActivityManagerService extends IActivityManager.Stub
if (disableHiddenApiChecks || disableTestApiChecks) {
enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS,
"disable hidden API checks");
-
- enableTestApiAccess(ai.packageName);
}
final long origId = Binder.clearCallingIdentity();
@@ -13576,8 +13554,8 @@ public class ActivityManagerService extends IActivityManager.Stub
mUsageStatsService.reportEvent(ii.targetPackage, userId,
UsageEvents.Event.SYSTEM_INTERACTION);
}
- app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks, abiOverride,
- ZYGOTE_POLICY_FLAG_EMPTY);
+ app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks,
+ disableTestApiChecks, abiOverride, ZYGOTE_POLICY_FLAG_EMPTY);
}
app.setActiveInstrumentation(activeInstr);
@@ -13732,25 +13710,6 @@ public class ActivityManagerService extends IActivityManager.Stub
app.userId,
"finished inst");
}
-
- disableTestApiAccess(app.info.packageName);
- }
-
- private void enableTestApiAccess(String packageName) {
- if (mPlatformCompat != null) {
- Compatibility.ChangeConfig config = new Compatibility.ChangeConfig(
- Collections.singleton(166236554L /* VMRuntime.ALLOW_TEST_API_ACCESS */),
- Collections.emptySet());
- CompatibilityChangeConfig override = new CompatibilityChangeConfig(config);
- mPlatformCompat.setOverridesForTest(override, packageName);
- }
- }
-
- private void disableTestApiAccess(String packageName) {
- if (mPlatformCompat != null) {
- mPlatformCompat.clearOverrideForTest(166236554L /* VMRuntime.ALLOW_TEST_API_ACCESS */,
- packageName);
- }
}
public void finishInstrumentation(IApplicationThread target,
@@ -13959,7 +13918,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
void noteUidProcessState(final int uid, final int state,
- final @ActivityManager.ProcessCapability int capability) {
+ final @ProcessCapability int capability) {
mBatteryStatsService.noteUidProcessState(uid, state);
mAppOpsService.updateUidProcState(uid, state, capability);
if (mTrackingAssociations) {
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 7bdf43c9c744..a34163cd5fa2 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -66,6 +66,10 @@ public final class CachedAppOptimizer {
@VisibleForTesting static final String KEY_COMPACT_THROTTLE_4 = "compact_throttle_4";
@VisibleForTesting static final String KEY_COMPACT_THROTTLE_5 = "compact_throttle_5";
@VisibleForTesting static final String KEY_COMPACT_THROTTLE_6 = "compact_throttle_6";
+ @VisibleForTesting static final String KEY_COMPACT_THROTTLE_MIN_OOM_ADJ =
+ "compact_throttle_min_oom_adj";
+ @VisibleForTesting static final String KEY_COMPACT_THROTTLE_MAX_OOM_ADJ =
+ "compact_throttle_max_oom_adj";
@VisibleForTesting static final String KEY_COMPACT_STATSD_SAMPLE_RATE =
"compact_statsd_sample_rate";
@VisibleForTesting static final String KEY_FREEZER_STATSD_SAMPLE_RATE =
@@ -101,6 +105,10 @@ public final class CachedAppOptimizer {
@VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_4 = 10_000;
@VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_5 = 10 * 60 * 1000;
@VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_6 = 10 * 60 * 1000;
+ @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ =
+ ProcessList.CACHED_APP_MIN_ADJ;
+ @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ =
+ ProcessList.CACHED_APP_MAX_ADJ;
// The sampling rate to push app compaction events into statsd for upload.
@VisibleForTesting static final float DEFAULT_STATSD_SAMPLE_RATE = 0.1f;
@VisibleForTesting static final long DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB = 12_000L;
@@ -186,6 +194,10 @@ public final class CachedAppOptimizer {
updateFullDeltaRssThrottle();
} else if (KEY_COMPACT_PROC_STATE_THROTTLE.equals(name)) {
updateProcStateThrottle();
+ } else if (KEY_COMPACT_THROTTLE_MIN_OOM_ADJ.equals(name)) {
+ updateMinOomAdjThrottle();
+ } else if (KEY_COMPACT_THROTTLE_MAX_OOM_ADJ.equals(name)) {
+ updateMaxOomAdjThrottle();
}
}
}
@@ -217,6 +229,12 @@ public final class CachedAppOptimizer {
@GuardedBy("mPhenotypeFlagLock")
@VisibleForTesting volatile long mCompactThrottlePersistent = DEFAULT_COMPACT_THROTTLE_6;
@GuardedBy("mPhenotypeFlagLock")
+ @VisibleForTesting volatile long mCompactThrottleMinOomAdj =
+ DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ;
+ @GuardedBy("mPhenotypeFlagLock")
+ @VisibleForTesting volatile long mCompactThrottleMaxOomAdj =
+ DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ;
+ @GuardedBy("mPhenotypeFlagLock")
private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION;
private volatile boolean mUseFreezer = DEFAULT_USE_FREEZER;
@GuardedBy("this")
@@ -282,6 +300,7 @@ public final class CachedAppOptimizer {
* starts the background thread if necessary.
*/
public void init() {
+ // TODO: initialize flags to default and only update them if values are set in DeviceConfig
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
ActivityThread.currentApplication().getMainExecutor(), mOnFlagsChangedListener);
synchronized (mPhenotypeFlagLock) {
@@ -294,6 +313,8 @@ public final class CachedAppOptimizer {
updateFullDeltaRssThrottle();
updateProcStateThrottle();
updateUseFreezer();
+ updateMinOomAdjThrottle();
+ updateMaxOomAdjThrottle();
}
}
@@ -328,6 +349,8 @@ public final class CachedAppOptimizer {
pw.println(" " + KEY_COMPACT_THROTTLE_4 + "=" + mCompactThrottleFullFull);
pw.println(" " + KEY_COMPACT_THROTTLE_5 + "=" + mCompactThrottleBFGS);
pw.println(" " + KEY_COMPACT_THROTTLE_6 + "=" + mCompactThrottlePersistent);
+ pw.println(" " + KEY_COMPACT_THROTTLE_MIN_OOM_ADJ + "=" + mCompactThrottleMinOomAdj);
+ pw.println(" " + KEY_COMPACT_THROTTLE_MAX_OOM_ADJ + "=" + mCompactThrottleMaxOomAdj);
pw.println(" " + KEY_COMPACT_STATSD_SAMPLE_RATE + "=" + mCompactStatsdSampleRate);
pw.println(" " + KEY_COMPACT_FULL_RSS_THROTTLE_KB + "="
+ mFullAnonRssThrottleKb);
@@ -367,12 +390,23 @@ public final class CachedAppOptimizer {
@GuardedBy("mProcLock")
void compactAppFull(ProcessRecord app) {
- app.mOptRecord.setReqCompactAction(COMPACT_PROCESS_FULL);
- mPendingCompactionProcesses.add(app);
- mCompactionHandler.sendMessage(
+ // Apply OOM adj score throttle for Full App Compaction.
+ if ((app.mState.getSetAdj() < mCompactThrottleMinOomAdj
+ || app.mState.getSetAdj() > mCompactThrottleMaxOomAdj)
+ && app.mState.getCurAdj() >= mCompactThrottleMinOomAdj
+ && app.mState.getCurAdj() <= mCompactThrottleMaxOomAdj) {
+ app.mOptRecord.setReqCompactAction(COMPACT_PROCESS_FULL);
+ mPendingCompactionProcesses.add(app);
+ mCompactionHandler.sendMessage(
mCompactionHandler.obtainMessage(
- COMPACT_PROCESS_MSG, app.mState.getSetAdj(), app.mState.getSetProcState()));
-
+ COMPACT_PROCESS_MSG, app.mState.getSetAdj(), app.mState.getSetProcState()));
+ } else {
+ if (DEBUG_COMPACTION) {
+ Slog.d(TAG_AM, "Skipping full compaction for " + app.processName
+ + " oom adj score changed from " + app.mState.getSetAdj()
+ + " to " + app.mState.getCurAdj());
+ }
+ }
}
@GuardedBy("mProcLock")
@@ -629,6 +663,7 @@ public final class CachedAppOptimizer {
@GuardedBy("mPhenotypeFlagLock")
private void updateCompactionThrottles() {
boolean useThrottleDefaults = false;
+ // TODO: improve efficiency by calling DeviceConfig only once for all flags.
String throttleSomeSomeFlag =
DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_COMPACT_THROTTLE_1);
@@ -647,12 +682,20 @@ public final class CachedAppOptimizer {
String throttlePersistentFlag =
DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_COMPACT_THROTTLE_6);
+ String throttleMinOomAdjFlag =
+ DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_COMPACT_THROTTLE_MIN_OOM_ADJ);
+ String throttleMaxOomAdjFlag =
+ DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_COMPACT_THROTTLE_MAX_OOM_ADJ);
if (TextUtils.isEmpty(throttleSomeSomeFlag) || TextUtils.isEmpty(throttleSomeFullFlag)
|| TextUtils.isEmpty(throttleFullSomeFlag)
|| TextUtils.isEmpty(throttleFullFullFlag)
|| TextUtils.isEmpty(throttleBFGSFlag)
- || TextUtils.isEmpty(throttlePersistentFlag)) {
+ || TextUtils.isEmpty(throttlePersistentFlag)
+ || TextUtils.isEmpty(throttleMinOomAdjFlag)
+ || TextUtils.isEmpty(throttleMaxOomAdjFlag)) {
// Set defaults for all if any are not set.
useThrottleDefaults = true;
} else {
@@ -663,6 +706,8 @@ public final class CachedAppOptimizer {
mCompactThrottleFullFull = Integer.parseInt(throttleFullFullFlag);
mCompactThrottleBFGS = Integer.parseInt(throttleBFGSFlag);
mCompactThrottlePersistent = Integer.parseInt(throttlePersistentFlag);
+ mCompactThrottleMinOomAdj = Long.parseLong(throttleMinOomAdjFlag);
+ mCompactThrottleMaxOomAdj = Long.parseLong(throttleMaxOomAdjFlag);
} catch (NumberFormatException e) {
useThrottleDefaults = true;
}
@@ -675,6 +720,8 @@ public final class CachedAppOptimizer {
mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4;
mCompactThrottleBFGS = DEFAULT_COMPACT_THROTTLE_5;
mCompactThrottlePersistent = DEFAULT_COMPACT_THROTTLE_6;
+ mCompactThrottleMinOomAdj = DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ;
+ mCompactThrottleMaxOomAdj = DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ;
}
}
@@ -729,6 +776,28 @@ public final class CachedAppOptimizer {
}
}
+ @GuardedBy("mPhenotypeFlagLock")
+ private void updateMinOomAdjThrottle() {
+ mCompactThrottleMinOomAdj = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_COMPACT_THROTTLE_MIN_OOM_ADJ, DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ);
+
+ // Should only compact cached processes.
+ if (mCompactThrottleMinOomAdj < ProcessList.CACHED_APP_MIN_ADJ) {
+ mCompactThrottleMinOomAdj = DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ;
+ }
+ }
+
+ @GuardedBy("mPhenotypeFlagLock")
+ private void updateMaxOomAdjThrottle() {
+ mCompactThrottleMaxOomAdj = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_COMPACT_THROTTLE_MAX_OOM_ADJ, DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ);
+
+ // Should only compact cached processes.
+ if (mCompactThrottleMaxOomAdj > ProcessList.CACHED_APP_MAX_ADJ) {
+ mCompactThrottleMaxOomAdj = DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ;
+ }
+ }
+
private boolean parseProcStateThrottle(String procStateThrottleString) {
String[] procStates = TextUtils.split(procStateThrottleString, ",");
mProcStateThrottle.clear();
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 0a8016cf0556..b956e306dc3f 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -21,6 +21,7 @@ import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL_IMPLICIT;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_NETWORK;
import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
@@ -1981,6 +1982,21 @@ public final class OomAdjuster {
capability |= cstate.getCurCapability();
}
+ // If an app has network capability by default
+ // (by having procstate <= BFGS), then the apps it binds to will get
+ // elevated to a high enough procstate anyway to get network unless they
+ // request otherwise, so don't propagate the network capability by default
+ // in this case unless they explicitly request it.
+ if ((cstate.getCurCapability() & PROCESS_CAPABILITY_NETWORK) != 0) {
+ if (clientProcState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+ if ((cr.flags & Context.BIND_ALLOW_NETWORK_ACCESS) != 0) {
+ capability |= PROCESS_CAPABILITY_NETWORK;
+ }
+ } else {
+ capability |= PROCESS_CAPABILITY_NETWORK;
+ }
+ }
+
if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
// If the other app is cached for any reason, for purposes here
// we are going to consider it empty. The specific cached state
@@ -2048,6 +2064,10 @@ public final class OomAdjuster {
&& clientAdj <= ProcessList.PERCEPTIBLE_APP_ADJ
&& adj >= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
newAdj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
+ } else if ((cr.flags & Context.BIND_ALMOST_PERCEPTIBLE) != 0
+ && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
+ && adj >= ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ) {
+ newAdj = ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ;
} else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
&& clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
&& adj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -2117,13 +2137,13 @@ public final class OomAdjuster {
if (enabled) {
if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
// TOP process passes all capabilities to the service.
- capability |= PROCESS_CAPABILITY_ALL;
+ capability |= cstate.getCurCapability();
} else {
// TOP process passes no capability to the service.
}
} else {
// TOP process passes all capabilities to the service.
- capability |= PROCESS_CAPABILITY_ALL;
+ capability |= cstate.getCurCapability();
}
}
} else if ((cr.flags & Context.BIND_IMPORTANT_BACKGROUND) == 0) {
@@ -2448,20 +2468,20 @@ public final class OomAdjuster {
case PROCESS_STATE_TOP:
return PROCESS_CAPABILITY_ALL;
case PROCESS_STATE_BOUND_TOP:
- return PROCESS_CAPABILITY_NONE;
+ return PROCESS_CAPABILITY_NETWORK;
case PROCESS_STATE_FOREGROUND_SERVICE:
if (psr.hasForegroundServices()) {
// Capability from FGS are conditional depending on foreground service type in
// manifest file and the mAllowWhileInUsePermissionInFgs flag.
- return PROCESS_CAPABILITY_NONE;
+ return PROCESS_CAPABILITY_NETWORK;
} else {
// process has no FGS, the PROCESS_STATE_FOREGROUND_SERVICE is from client.
// the implicit capability could be removed in the future, client should use
// BIND_INCLUDE_CAPABILITY flag.
- return PROCESS_CAPABILITY_ALL_IMPLICIT;
+ return PROCESS_CAPABILITY_ALL_IMPLICIT | PROCESS_CAPABILITY_NETWORK;
}
case PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
- return PROCESS_CAPABILITY_NONE;
+ return PROCESS_CAPABILITY_NETWORK;
default:
return PROCESS_CAPABILITY_NONE;
}
@@ -2541,9 +2561,7 @@ public final class OomAdjuster {
&& (state.getCurAdj() == ProcessList.PREVIOUS_APP_ADJ
|| state.getCurAdj() == ProcessList.HOME_APP_ADJ)) {
mCachedAppOptimizer.compactAppSome(app);
- } else if ((state.getSetAdj() < ProcessList.CACHED_APP_MIN_ADJ
- || state.getSetAdj() > ProcessList.CACHED_APP_MAX_ADJ)
- && state.getCurAdj() >= ProcessList.CACHED_APP_MIN_ADJ
+ } else if (state.getCurAdj() >= ProcessList.CACHED_APP_MIN_ADJ
&& state.getCurAdj() <= ProcessList.CACHED_APP_MAX_ADJ) {
mCachedAppOptimizer.compactAppFull(app);
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 172f7073852a..38330fe770fb 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
@@ -57,6 +58,7 @@ import static com.android.server.am.AppProfiler.TAG_PSS;
import android.annotation.NonNull;
import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessCapability;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppProtoEnums;
@@ -228,6 +230,11 @@ public final class ProcessList {
// not so perceptible that it affects the user immediately if killed.
static final int PERCEPTIBLE_LOW_APP_ADJ = 250;
+ // This is a process hosting services that are not perceptible to the user but the
+ // client (system) binding to it requested to treat it as if it is perceptible and avoid killing
+ // it if possible.
+ static final int PERCEPTIBLE_MEDIUM_APP_ADJ = 225;
+
// This is a process only hosting components that are perceptible to the
// user, and we really want to avoid killing them, but they are not
// immediately visible. An example is background music playback.
@@ -1027,6 +1034,9 @@ public final class ProcessList {
} else if (setAdj >= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
return buildOomTag("prcl ", "prcl", null, setAdj,
ProcessList.PERCEPTIBLE_LOW_APP_ADJ, compact);
+ } else if (setAdj >= ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ) {
+ return buildOomTag("prcm ", "prcm", null, setAdj,
+ ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ, compact);
} else if (setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
return buildOomTag("prcp ", "prcp", null, setAdj,
ProcessList.PERCEPTIBLE_APP_ADJ, compact);
@@ -1054,76 +1064,7 @@ public final class ProcessList {
}
public static String makeProcStateString(int curProcState) {
- String procState;
- switch (curProcState) {
- case ActivityManager.PROCESS_STATE_PERSISTENT:
- procState = "PER ";
- break;
- case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
- procState = "PERU";
- break;
- case ActivityManager.PROCESS_STATE_TOP:
- procState = "TOP ";
- break;
- case ActivityManager.PROCESS_STATE_BOUND_TOP:
- procState = "BTOP";
- break;
- case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
- procState = "FGS ";
- break;
- case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
- procState = "BFGS";
- break;
- case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
- procState = "IMPF";
- break;
- case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
- procState = "IMPB";
- break;
- case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
- procState = "TRNB";
- break;
- case ActivityManager.PROCESS_STATE_BACKUP:
- procState = "BKUP";
- break;
- case ActivityManager.PROCESS_STATE_SERVICE:
- procState = "SVC ";
- break;
- case ActivityManager.PROCESS_STATE_RECEIVER:
- procState = "RCVR";
- break;
- case ActivityManager.PROCESS_STATE_TOP_SLEEPING:
- procState = "TPSL";
- break;
- case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
- procState = "HVY ";
- break;
- case ActivityManager.PROCESS_STATE_HOME:
- procState = "HOME";
- break;
- case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
- procState = "LAST";
- break;
- case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
- procState = "CAC ";
- break;
- case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
- procState = "CACC";
- break;
- case ActivityManager.PROCESS_STATE_CACHED_RECENT:
- procState = "CRE ";
- break;
- case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
- procState = "CEM ";
- break;
- case ActivityManager.PROCESS_STATE_NONEXISTENT:
- procState = "NONE";
- break;
- default:
- procState = "??";
- break;
- }
- return procState;
+ return ActivityManager.procStateToString(curProcState);
}
public static int makeProcStateProtoEnum(int curProcState) {
@@ -1828,7 +1769,8 @@ public final class ProcessList {
*/
@GuardedBy("mService")
boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
- int zygotePolicyFlags, boolean disableHiddenApiChecks, String abiOverride) {
+ int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,
+ String abiOverride) {
if (app.isPendingStart()) {
return true;
}
@@ -1974,6 +1916,10 @@ public final class ProcessList {
throw new IllegalStateException("Invalid API policy: " + policy);
}
runtimeFlags |= policyBits;
+
+ if (disableTestApiChecks) {
+ runtimeFlags |= Zygote.DISABLE_TEST_API_ENFORCEMENT_POLICY;
+ }
}
String useAppImageCache = SystemProperties.get(
@@ -2437,7 +2383,8 @@ public final class ProcessList {
boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
int zygotePolicyFlags, String abiOverride) {
return startProcessLocked(app, hostingRecord, zygotePolicyFlags,
- false /* disableHiddenApiChecks */, abiOverride);
+ false /* disableHiddenApiChecks */, false /* disableTestApiChecks */,
+ abiOverride);
}
@GuardedBy("mService")
@@ -4458,6 +4405,7 @@ public final class ProcessList {
printOomLevel(pw, "FOREGROUND_APP_ADJ", FOREGROUND_APP_ADJ);
printOomLevel(pw, "VISIBLE_APP_ADJ", VISIBLE_APP_ADJ);
printOomLevel(pw, "PERCEPTIBLE_APP_ADJ", PERCEPTIBLE_APP_ADJ);
+ printOomLevel(pw, "PERCEPTIBLE_MEDIUM_APP_ADJ", PERCEPTIBLE_MEDIUM_APP_ADJ);
printOomLevel(pw, "PERCEPTIBLE_LOW_APP_ADJ", PERCEPTIBLE_LOW_APP_ADJ);
printOomLevel(pw, "BACKUP_APP_ADJ", BACKUP_APP_ADJ);
printOomLevel(pw, "HEAVY_WEIGHT_APP_ADJ", HEAVY_WEIGHT_APP_ADJ);
@@ -4721,13 +4669,26 @@ public final class ProcessList {
}
}
- /** Returns the uid's process state or PROCESS_STATE_NONEXISTENT if not running */
+ /**
+ * Returns the uid's process state or {@link ActivityManager#PROCESS_STATE_NONEXISTENT}
+ * if not running
+ */
@GuardedBy(anyOf = {"mService", "mProcLock"})
int getUidProcStateLOSP(int uid) {
UidRecord uidRec = mActiveUids.get(uid);
return uidRec == null ? PROCESS_STATE_NONEXISTENT : uidRec.getCurProcState();
}
+ /**
+ * Returns the uid's process capability or {@link ActivityManager#PROCESS_CAPABILITY_NONE}
+ * if not running
+ */
+ @GuardedBy(anyOf = {"mService", "mProcLock"})
+ @ProcessCapability int getUidProcessCapabilityLOSP(int uid) {
+ UidRecord uidRec = mActiveUids.get(uid);
+ return uidRec == null ? PROCESS_CAPABILITY_NONE : uidRec.getCurCapability();
+ }
+
/** Returns the UidRecord for the given uid, if it exists. */
@GuardedBy(anyOf = {"mService", "mProcLock"})
UidRecord getUidRecordLOSP(int uid) {
@@ -4768,11 +4729,13 @@ public final class ProcessList {
int getBlockStateForUid(UidRecord uidRec) {
// Denotes whether uid's process state is currently allowed network access.
final boolean isAllowed =
- isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.getCurProcState())
+ isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.getCurProcState(),
+ uidRec.getCurCapability())
|| isProcStateAllowedWhileOnRestrictBackground(uidRec.getCurProcState());
// Denotes whether uid's process state was previously allowed network access.
final boolean wasAllowed =
- isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.getSetProcState())
+ isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.getSetProcState(),
+ uidRec.getSetCapability())
|| isProcStateAllowedWhileOnRestrictBackground(uidRec.getSetProcState());
// When the uid is coming to foreground, AMS should inform the app thread that it should
@@ -4810,8 +4773,9 @@ public final class ProcessList {
if (!UserHandle.isApp(uidRec.getUid()) || !uidRec.hasInternetPermission) {
continue;
}
- // If process state is not changed, then there's nothing to do.
- if (uidRec.getSetProcState() == uidRec.getCurProcState()) {
+ // If process state and capabilities are not changed, then there's nothing to do.
+ if (uidRec.getSetProcState() == uidRec.getCurProcState()
+ && uidRec.getSetCapability() == uidRec.getCurCapability()) {
continue;
}
final int blockState = getBlockStateForUid(uidRec);
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index e97f0b47380a..33bdac270c53 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -23,9 +23,12 @@ import static android.content.Intent.EXTRA_REPLACING;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION;
+import static com.android.server.apphibernation.AppHibernationConstants.KEY_APP_HIBERNATION_ENABLED;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityThread;
import android.app.IActivityManager;
import android.apphibernation.IAppHibernationService;
import android.content.BroadcastReceiver;
@@ -45,6 +48,8 @@ import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
@@ -93,6 +98,9 @@ public final class AppHibernationService extends SystemService {
private final HibernationStateDiskStore<GlobalLevelState> mGlobalLevelHibernationDiskStore;
private final Injector mInjector;
+ @VisibleForTesting
+ boolean mIsServiceEnabled;
+
/**
* Initializes the system service.
* <p>
@@ -139,6 +147,13 @@ public final class AppHibernationService extends SystemService {
initializeGlobalHibernationStates(states);
}
}
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ mIsServiceEnabled = isAppHibernationEnabled();
+ DeviceConfig.addOnPropertiesChangedListener(
+ NAMESPACE_APP_HIBERNATION,
+ ActivityThread.currentApplication().getMainExecutor(),
+ this::onDeviceConfigChanged);
+ }
}
/**
@@ -149,6 +164,10 @@ public final class AppHibernationService extends SystemService {
* @return true if package is hibernating for the user
*/
boolean isHibernatingForUser(String packageName, int userId) {
+ if (!checkHibernationEnabled("isHibernatingForUser")) {
+ return false;
+ }
+
userId = handleIncomingUser(userId, "isHibernating");
if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
Slog.e(TAG, "Attempt to get hibernation state of stopped or nonexistent user "
@@ -174,6 +193,9 @@ public final class AppHibernationService extends SystemService {
* @param packageName package to check
*/
boolean isHibernatingGlobally(String packageName) {
+ if (!checkHibernationEnabled("isHibernatingGlobally")) {
+ return false;
+ }
synchronized (mLock) {
GlobalLevelState state = mGlobalHibernationStates.get(packageName);
if (state == null) {
@@ -192,6 +214,9 @@ public final class AppHibernationService extends SystemService {
* @param isHibernating new hibernation state
*/
void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
+ if (!checkHibernationEnabled("setHibernatingForUser")) {
+ return;
+ }
userId = handleIncomingUser(userId, "setHibernating");
if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
Slog.w(TAG, "Attempt to set hibernation state for a stopped or nonexistent user "
@@ -229,6 +254,9 @@ public final class AppHibernationService extends SystemService {
* @param isHibernating new hibernation state
*/
void setHibernatingGlobally(String packageName, boolean isHibernating) {
+ if (!checkHibernationEnabled("setHibernatingGlobally")) {
+ return;
+ }
synchronized (mLock) {
GlobalLevelState state = mGlobalHibernationStates.get(packageName);
if (state == null) {
@@ -421,6 +449,9 @@ public final class AppHibernationService extends SystemService {
private void onPackageAdded(@NonNull String packageName, int userId) {
synchronized (mLock) {
+ if (!mUserStates.contains(userId)) {
+ return;
+ }
UserLevelState userState = new UserLevelState();
userState.packageName = packageName;
mUserStates.get(userId).put(packageName, userState);
@@ -434,6 +465,9 @@ public final class AppHibernationService extends SystemService {
private void onPackageRemoved(@NonNull String packageName, int userId) {
synchronized (mLock) {
+ if (!mUserStates.contains(userId)) {
+ return;
+ }
mUserStates.get(userId).remove(packageName);
}
}
@@ -444,6 +478,15 @@ public final class AppHibernationService extends SystemService {
}
}
+ private void onDeviceConfigChanged(Properties properties) {
+ for (String key : properties.getKeyset()) {
+ if (TextUtils.equals(KEY_APP_HIBERNATION_ENABLED, key)) {
+ mIsServiceEnabled = isAppHibernationEnabled();
+ break;
+ }
+ }
+ }
+
/**
* Private helper method to get the real user id and enforce permission checks.
*
@@ -461,6 +504,13 @@ public final class AppHibernationService extends SystemService {
}
}
+ private boolean checkHibernationEnabled(String methodName) {
+ if (!mIsServiceEnabled) {
+ Slog.w(TAG, String.format("Attempted to call %s on unsupported device.", methodName));
+ }
+ return mIsServiceEnabled;
+ }
+
private final AppHibernationServiceStub mServiceStub = new AppHibernationServiceStub(this);
static final class AppHibernationServiceStub extends IAppHibernationService.Stub {
@@ -536,7 +586,7 @@ public final class AppHibernationService extends SystemService {
public static boolean isAppHibernationEnabled() {
return DeviceConfig.getBoolean(
NAMESPACE_APP_HIBERNATION,
- AppHibernationConstants.KEY_APP_HIBERNATION_ENABLED,
+ KEY_APP_HIBERNATION_ENABLED,
false /* defaultValue */);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 5f3405379715..f5b94177a2d9 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -8570,6 +8570,7 @@ public class AudioService extends IAudioService.Stub
public void postDisplaySafeVolumeWarning(int flags) {
if (mController == null)
return;
+ flags = flags | AudioManager.FLAG_SHOW_UI;
try {
mController.displaySafeVolumeWarning(flags);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ReEnrollNotificationUtils.java b/services/core/java/com/android/server/biometrics/sensors/face/ReEnrollNotificationUtils.java
new file mode 100644
index 000000000000..f35a5208f6ed
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/ReEnrollNotificationUtils.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors.face;
+
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserHandle;
+
+import com.android.internal.R;
+
+public class ReEnrollNotificationUtils {
+
+ private static final String NOTIFICATION_TAG = "FaceService";
+ private static final int NOTIFICATION_ID = 1;
+
+ public static void showReEnrollmentNotification(@NonNull Context context) {
+ final NotificationManager notificationManager =
+ context.getSystemService(NotificationManager.class);
+
+ final String name =
+ context.getString(R.string.face_recalibrate_notification_name);
+ final String title =
+ context.getString(R.string.face_recalibrate_notification_title);
+ final String content =
+ context.getString(R.string.face_recalibrate_notification_content);
+
+ final Intent intent = new Intent("android.settings.FACE_SETTINGS");
+ intent.setPackage("com.android.settings");
+
+ final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context,
+ 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */,
+ null /* options */, UserHandle.CURRENT);
+
+ final String channelName = "FaceEnrollNotificationChannel";
+
+ final NotificationChannel channel = new NotificationChannel(channelName, name,
+ NotificationManager.IMPORTANCE_HIGH);
+ final Notification notification = new Notification.Builder(context, channelName)
+ .setSmallIcon(R.drawable.ic_lock)
+ .setContentTitle(title)
+ .setContentText(content)
+ .setSubText(name)
+ .setOnlyAlertOnce(true)
+ .setLocalOnly(true)
+ .setAutoCancel(true)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setContentIntent(pendingIntent)
+ .setVisibility(Notification.VISIBILITY_SECRET)
+ .build();
+
+ notificationManager.createNotificationChannel(channel);
+ notificationManager.notifyAsUser(NOTIFICATION_TAG,
+ NOTIFICATION_ID, notification,
+ UserHandle.CURRENT);
+ }
+
+ public static void cancelNotification(@NonNull Context context) {
+ final NotificationManager notificationManager =
+ context.getSystemService(NotificationManager.class);
+ notificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID, UserHandle.CURRENT);
+ }
+
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index 8f554028ebfd..089cf1e4cee8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -41,6 +41,7 @@ import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutConsumer;
import com.android.server.biometrics.sensors.LockoutTracker;
+import com.android.server.biometrics.sensors.face.ReEnrollNotificationUtils;
import com.android.server.biometrics.sensors.face.UsageStats;
import java.util.ArrayList;
@@ -163,6 +164,9 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
vibrateError();
}
break;
+ case BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL:
+ ReEnrollNotificationUtils.showReEnrollmentNotification(getContext());
+ break;
default:
break;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
index 898d81b0c8c4..0eb51fdba159 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
@@ -41,6 +41,7 @@ import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.EnrollClient;
import com.android.server.biometrics.sensors.face.FaceUtils;
+import com.android.server.biometrics.sensors.face.ReEnrollNotificationUtils;
import java.io.IOException;
import java.util.ArrayList;
@@ -85,6 +86,13 @@ public class FaceEnrollClient extends EnrollClient<ISession> {
}
@Override
+ public void start(@NonNull Callback callback) {
+ super.start(callback);
+
+ ReEnrollNotificationUtils.cancelNotification(getContext());
+ }
+
+ @Override
public void destroy() {
try {
AidlNativeHandleUtils.close(mPreviewSurface);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index ee8823e041bc..1b9bd7fd0cea 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -19,7 +19,6 @@ package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.NotificationManager;
import android.app.SynchronousUserSwitchObserver;
import android.app.UserSwitchObserver;
import android.content.Context;
@@ -71,6 +70,7 @@ import com.android.server.biometrics.sensors.PerformanceTracker;
import com.android.server.biometrics.sensors.RemovalConsumer;
import com.android.server.biometrics.sensors.face.FaceUtils;
import com.android.server.biometrics.sensors.face.LockoutHalImpl;
+import com.android.server.biometrics.sensors.face.ReEnrollNotificationUtils;
import com.android.server.biometrics.sensors.face.ServiceProvider;
import com.android.server.biometrics.sensors.face.UsageStats;
@@ -96,8 +96,6 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
private static final String TAG = "Face10";
private static final int ENROLL_TIMEOUT_SEC = 75;
- static final String NOTIFICATION_TAG = "FaceService";
- static final int NOTIFICATION_ID = 1;
private boolean mTestHalEnabled;
@@ -109,7 +107,6 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
@NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
@NonNull private final LockoutHalImpl mLockoutTracker;
@NonNull private final UsageStats mUsageStats;
- @NonNull private final NotificationManager mNotificationManager;
@NonNull private final Map<Integer, Long> mAuthenticatorIds;
@Nullable private IBiometricsFace mDaemon;
@NonNull private final HalResultController mHalResultController;
@@ -343,7 +340,6 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
mUsageStats = new UsageStats(context);
mAuthenticatorIds = new HashMap<>();
mLazyDaemon = Face10.this::getDaemon;
- mNotificationManager = mContext.getSystemService(NotificationManager.class);
mLockoutTracker = new LockoutHalImpl();
mLockoutResetDispatcher = lockoutResetDispatcher;
mHalResultController = new HalResultController(sensorId, context, mHandler, mScheduler,
@@ -607,8 +603,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
- mNotificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID,
- UserHandle.CURRENT);
+ ReEnrollNotificationUtils.cancelNotification(mContext);
final FaceEnrollClient client = new FaceEnrollClient(mContext, mLazyDaemon, token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index a4b3ac57a4df..3ca51d32797e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -17,12 +17,7 @@
package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
import android.content.Context;
-import android.content.Intent;
import android.content.res.Resources;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
@@ -32,7 +27,6 @@ import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.face.FaceManager;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.util.Slog;
import com.android.internal.R;
@@ -40,6 +34,7 @@ import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutTracker;
+import com.android.server.biometrics.sensors.face.ReEnrollNotificationUtils;
import com.android.server.biometrics.sensors.face.UsageStats;
import java.util.ArrayList;
@@ -52,7 +47,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
private static final String TAG = "FaceAuthenticationClient";
- private final NotificationManager mNotificationManager;
+
private final UsageStats mUsageStats;
private final int[] mBiometricPromptIgnoreList;
@@ -72,7 +67,6 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
lockoutTracker, isKeyguard);
- mNotificationManager = context.getSystemService(NotificationManager.class);
mUsageStats = usageStats;
final Resources resources = getContext().getResources();
@@ -188,41 +182,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
mLastAcquire = acquireInfo;
if (acquireInfo == FaceManager.FACE_ACQUIRED_RECALIBRATE) {
- final String name =
- getContext().getString(R.string.face_recalibrate_notification_name);
- final String title =
- getContext().getString(R.string.face_recalibrate_notification_title);
- final String content =
- getContext().getString(R.string.face_recalibrate_notification_content);
-
- final Intent intent = new Intent("android.settings.FACE_SETTINGS");
- intent.setPackage("com.android.settings");
-
- final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(getContext(),
- 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */,
- null /* options */, UserHandle.CURRENT);
-
- final String channelName = "FaceEnrollNotificationChannel";
-
- NotificationChannel channel = new NotificationChannel(channelName, name,
- NotificationManager.IMPORTANCE_HIGH);
- Notification notification = new Notification.Builder(getContext(), channelName)
- .setSmallIcon(R.drawable.ic_lock)
- .setContentTitle(title)
- .setContentText(content)
- .setSubText(name)
- .setOnlyAlertOnce(true)
- .setLocalOnly(true)
- .setAutoCancel(true)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setContentIntent(pendingIntent)
- .setVisibility(Notification.VISIBILITY_SECRET)
- .build();
-
- mNotificationManager.createNotificationChannel(channel);
- mNotificationManager.notifyAsUser(Face10.NOTIFICATION_TAG,
- Face10.NOTIFICATION_ID, notification,
- UserHandle.CURRENT);
+ ReEnrollNotificationUtils.showReEnrollmentNotification(getContext());
}
final boolean shouldSend = shouldSend(acquireInfo, vendorCode);
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 46c49e7fc28c..641287f0f435 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -16,6 +16,8 @@
package com.android.server.connectivity;
+import static com.android.net.module.util.CollectionUtils.contains;
+
import android.annotation.NonNull;
import android.net.ConnectivityManager;
import android.net.IDnsResolver;
@@ -33,7 +35,6 @@ import android.os.ServiceSpecificException;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.android.net.module.util.NetworkStackConstants;
import com.android.server.net.BaseNetworkObserver;
@@ -117,8 +118,8 @@ public class Nat464Xlat extends BaseNetworkObserver {
@VisibleForTesting
protected static boolean requiresClat(NetworkAgentInfo nai) {
// TODO: migrate to NetworkCapabilities.TRANSPORT_*.
- final boolean supported = ArrayUtils.contains(NETWORK_TYPES, nai.networkInfo.getType());
- final boolean connected = ArrayUtils.contains(NETWORK_STATES, nai.networkInfo.getState());
+ final boolean supported = contains(NETWORK_TYPES, nai.networkInfo.getType());
+ final boolean connected = contains(NETWORK_STATES, nai.networkInfo.getState());
// Only run clat on networks that have a global IPv6 address and don't have a native IPv4
// address.
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 8bf188696c27..9411e33434d8 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -28,6 +28,8 @@ import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
+import static com.android.net.module.util.CollectionUtils.toIntArray;
+
import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -40,23 +42,21 @@ import android.net.UidRange;
import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import android.os.SystemConfigManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.system.OsConstants;
-import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.CollectionUtils;
import com.android.server.LocalServices;
-import com.android.server.SystemConfig;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -80,6 +80,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
private final PackageManager mPackageManager;
private final UserManager mUserManager;
+ private final SystemConfigManager mSystemConfigManager;
private final INetd mNetd;
private final Dependencies mDeps;
@@ -123,6 +124,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
@NonNull final Dependencies deps) {
mPackageManager = context.getPackageManager();
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ mSystemConfigManager = context.getSystemService(SystemConfigManager.class);
mNetd = netd;
mDeps = deps;
}
@@ -174,20 +176,18 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
mUsers.addAll(mUserManager.getUserHandles(true /* excludeDying */));
- final SparseArray<ArraySet<String>> systemPermission =
- SystemConfig.getInstance().getSystemPermissions();
- for (int i = 0; i < systemPermission.size(); i++) {
- ArraySet<String> perms = systemPermission.valueAt(i);
- int uid = systemPermission.keyAt(i);
- int netdPermission = 0;
- // Get the uids of native services that have UPDATE_DEVICE_STATS or INTERNET permission.
- if (perms != null) {
- netdPermission |= perms.contains(UPDATE_DEVICE_STATS)
- ? INetd.PERMISSION_UPDATE_DEVICE_STATS : 0;
- netdPermission |= perms.contains(INTERNET)
- ? INetd.PERMISSION_INTERNET : 0;
+ final SparseArray<String> netdPermToSystemPerm = new SparseArray<>();
+ netdPermToSystemPerm.put(INetd.PERMISSION_INTERNET, INTERNET);
+ netdPermToSystemPerm.put(INetd.PERMISSION_UPDATE_DEVICE_STATS, UPDATE_DEVICE_STATS);
+ for (int i = 0; i < netdPermToSystemPerm.size(); i++) {
+ final int netdPermission = netdPermToSystemPerm.keyAt(i);
+ final String systemPermission = netdPermToSystemPerm.valueAt(i);
+ final int[] hasPermissionUids =
+ mSystemConfigManager.getSystemPermissionUids(systemPermission);
+ for (int j = 0; j < hasPermissionUids.length; j++) {
+ final int uid = hasPermissionUids[j];
+ netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
}
- netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
}
log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
update(mUsers, mApps, true);
@@ -204,7 +204,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
return false;
}
- final int index = ArrayUtils.indexOf(app.requestedPermissions, permission);
+ final int index = CollectionUtils.indexOf(app.requestedPermissions, permission);
if (index < 0 || index >= app.requestedPermissionsFlags.length) return false;
return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0;
}
@@ -246,15 +246,6 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
return mApps.containsKey(uid);
}
- private int[] toIntArray(Collection<Integer> list) {
- int[] array = new int[list.size()];
- int i = 0;
- for (Integer item : list) {
- array[i++] = item;
- }
- return array;
- }
-
private void update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add) {
List<Integer> network = new ArrayList<>();
List<Integer> system = new ArrayList<>();
@@ -662,23 +653,23 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
if (allPermissionAppIds.size() != 0) {
mNetd.trafficSetNetPermForUids(
INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
- ArrayUtils.convertToIntArray(allPermissionAppIds));
+ toIntArray(allPermissionAppIds));
}
if (internetPermissionAppIds.size() != 0) {
mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
- ArrayUtils.convertToIntArray(internetPermissionAppIds));
+ toIntArray(internetPermissionAppIds));
}
if (updateStatsPermissionAppIds.size() != 0) {
mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
- ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
+ toIntArray(updateStatsPermissionAppIds));
}
if (noPermissionAppIds.size() != 0) {
mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE,
- ArrayUtils.convertToIntArray(noPermissionAppIds));
+ toIntArray(noPermissionAppIds));
}
if (uninstalledAppIds.size() != 0) {
mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED,
- ArrayUtils.convertToIntArray(uninstalledAppIds));
+ toIntArray(uninstalledAppIds));
}
} catch (RemoteException e) {
Log.e(TAG, "Pass appId list of special permission failed." + e);
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index a769e88f77d7..01ac81fb2cb5 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -113,6 +113,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
+import com.android.net.module.util.NetdUtils;
import com.android.net.module.util.NetworkStackConstants;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
@@ -1509,7 +1510,7 @@ public class Vpn {
if (start != -1) ranges.add(new UidRange(start, stop));
} else if (disallowedApplications != null) {
// Add all ranges for user skipping UIDs for disallowedApplications.
- final UidRange userRange = UidRange.createForUser(userId);
+ final UidRange userRange = UidRange.createForUser(UserHandle.of(userId));
int start = userRange.start;
for (int uid : getAppsUids(disallowedApplications, userId)) {
if (uid == start) {
@@ -1522,7 +1523,7 @@ public class Vpn {
if (start <= userRange.stop) ranges.add(new UidRange(start, userRange.stop));
} else {
// Add all UIDs for the user.
- ranges.add(UidRange.createForUser(userId));
+ ranges.add(UidRange.createForUser(UserHandle.of(userId)));
}
}
@@ -1531,7 +1532,7 @@ public class Vpn {
private static List<UidRange> uidRangesForUser(int userId, Set<UidRange> existingRanges) {
// UidRange#createForUser returns the entire range of UIDs available to a macro-user.
// This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE}
- final UidRange userRange = UidRange.createForUser(userId);
+ final UidRange userRange = UidRange.createForUser(UserHandle.of(userId));
final List<UidRange> ranges = new ArrayList<>();
for (UidRange range : existingRanges) {
if (userRange.containsRange(range)) {
@@ -2528,7 +2529,7 @@ public class Vpn {
address /* unused */,
address /* unused */,
network);
- mNms.setInterfaceUp(mTunnelIface.getInterfaceName());
+ NetdUtils.setInterfaceUp(mNetd, mTunnelIface.getInterfaceName());
mSession = mIkev2SessionCreator.createIkeSession(
mContext,
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index fe89903c02d7..7b9ca37b1639 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -264,6 +264,10 @@ public class SyncManager {
private final SyncLogger mLogger;
+ // NOTE: this is a temporary allow-list for testing purposes; it will be removed before release.
+ private final String[] mEjSyncAllowedPackages = new String[]{
+ "com.google.android.google", "com.android.frameworks.servicestests"};
+
private boolean isJobIdInUseLockedH(int jobId, List<JobInfo> pendingJobs) {
for (JobInfo job: pendingJobs) {
if (job.getId() == jobId) {
@@ -983,6 +987,14 @@ public class SyncManager {
}
}
+ final boolean scheduleAsEj =
+ extras.getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, false);
+ // NOTE: this is a temporary check for internal testing - to be removed before release.
+ if (scheduleAsEj && !ArrayUtils.contains(mEjSyncAllowedPackages, callingPackage)) {
+ throw new IllegalArgumentException(
+ callingPackage + " is not allowed to schedule a sync as an EJ yet.");
+ }
+
for (AccountAndUser account : accounts) {
// If userId is specified, do not sync accounts of other users
if (userId >= UserHandle.USER_SYSTEM && account.userId >= UserHandle.USER_SYSTEM
@@ -1490,6 +1502,12 @@ public class SyncManager {
+ logSafe(syncOperation.target));
backoff = new Pair<Long, Long>(SyncStorageEngine.NOT_IN_BACKOFF_MODE,
SyncStorageEngine.NOT_IN_BACKOFF_MODE);
+ } else {
+ // if an EJ is being backed-off but doesn't have SYNC_EXTRAS_IGNORE_BACKOFF set,
+ // reschedule it as a regular job
+ if (syncOperation.isScheduledAsExpeditedJob()) {
+ syncOperation.scheduleEjAsRegularJob = true;
+ }
}
long now = SystemClock.elapsedRealtime();
long backoffDelay = backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE ? 0
@@ -1640,6 +1658,10 @@ public class SyncManager {
b.setRequiresCharging(true);
}
+ if (syncOperation.isScheduledAsExpeditedJob() && !syncOperation.scheduleEjAsRegularJob) {
+ b.setExpedited(true);
+ }
+
if (syncOperation.syncExemptionFlag
== ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP) {
DeviceIdleInternal dic =
@@ -3951,6 +3973,9 @@ public class SyncManager {
if (key.equals(ContentResolver.SYNC_EXTRAS_EXPEDITED)) {
return true;
}
+ if (key.equals(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB)) {
+ return true;
+ }
if (key.equals(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS)) {
return true;
}
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index 478763531abc..c8654d1b36ee 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -103,6 +103,13 @@ public class SyncOperation {
/** Stores the number of times this sync operation failed and had to be retried. */
int retries;
+ /**
+ * Indicates if a sync that was originally scheduled as an EJ is being re-scheduled as a
+ * regular job. Specifically, this will be {@code true} if a sync is being backed-off but
+ * {@link ContentResolver#SYNC_EXTRAS_IGNORE_BACKOFF} is not set.
+ */
+ boolean scheduleEjAsRegularJob;
+
/** jobId of the JobScheduler job corresponding to this sync */
public int jobId;
@@ -408,6 +415,12 @@ public class SyncOperation {
if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
sb.append(" EXPEDITED");
}
+ if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, false)) {
+ sb.append(" EXPEDITED-JOB");
+ if (scheduleEjAsRegularJob) {
+ sb.append("(scheduled-as-regular)");
+ }
+ }
switch (syncExemptionFlag) {
case ContentResolver.SYNC_EXEMPTION_NONE:
break;
@@ -537,6 +550,11 @@ public class SyncOperation {
return mImmutableExtras.getBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING, false);
}
+ boolean isScheduledAsExpeditedJob() {
+ return mImmutableExtras.getBoolean(
+ ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, false);
+ }
+
boolean isAppStandbyExempted() {
return syncExemptionFlag != ContentResolver.SYNC_EXEMPTION_NONE;
}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 225da7ad87b3..a2b9b966dd46 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -354,6 +354,10 @@ class AutomaticBrightnessController {
}
}
+ public void stop() {
+ setLightSensorEnabled(false);
+ }
+
public boolean hasUserDataPoints() {
return mBrightnessMapper.hasUserDataPoints();
}
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index a186e334c5c0..06010f51e231 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -243,7 +243,6 @@ public class BrightnessTracker {
}
/** Stop listening for events */
- @VisibleForTesting
void stop() {
if (DEBUG) {
Slog.d(TAG, "Stop");
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 198ea3d3f66a..f2126987ff19 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -817,6 +817,12 @@ final class ColorFade {
}
DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
+ if (displayInfo == null) {
+ // displayInfo can be null if the associated display has been removed. There
+ // is a delay between the display being removed and ColorFade being dismissed.
+ return;
+ }
+
switch (displayInfo.rotation) {
case Surface.ROTATION_0:
t.setPosition(mSurfaceControl, 0, 0);
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index cd17cfef2726..b3070b7cf1ba 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -16,6 +16,7 @@
package com.android.server.display;
+import android.content.Context;
import android.graphics.Rect;
import android.hardware.display.DisplayViewport;
import android.os.IBinder;
@@ -38,12 +39,14 @@ abstract class DisplayDevice {
private final IBinder mDisplayToken;
private final String mUniqueId;
+ protected DisplayDeviceConfig mDisplayDeviceConfig;
// The display device does not manage these properties itself, they are set by
// the display manager service. The display device shouldn't really be looking at these.
private int mCurrentLayerStack = -1;
private int mCurrentOrientation = -1;
private Rect mCurrentLayerStackRect;
private Rect mCurrentDisplayRect;
+ private final Context mContext;
// The display device owns its surface, but it should only set it
// within a transaction from performTraversalLocked.
@@ -53,10 +56,13 @@ abstract class DisplayDevice {
// Do not use for any other purpose.
DisplayDeviceInfo mDebugLastLoggedDeviceInfo;
- public DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId) {
+ public DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId,
+ Context context) {
mDisplayAdapter = displayAdapter;
mDisplayToken = displayToken;
mUniqueId = uniqueId;
+ mDisplayDeviceConfig = null;
+ mContext = context;
}
/**
@@ -74,7 +80,10 @@ abstract class DisplayDevice {
* @return The DisplayDeviceConfig; {@code null} if not overridden.
*/
public DisplayDeviceConfig getDisplayDeviceConfig() {
- return null;
+ if (mDisplayDeviceConfig == null) {
+ mDisplayDeviceConfig = loadDisplayDeviceConfig();
+ }
+ return mDisplayDeviceConfig;
}
/**
@@ -292,4 +301,8 @@ abstract class DisplayDevice {
pw.println("mCurrentDisplayRect=" + mCurrentDisplayRect);
pw.println("mCurrentSurface=" + mCurrentSurface);
}
+
+ private DisplayDeviceConfig loadDisplayDeviceConfig() {
+ return DisplayDeviceConfig.create(mContext, false);
+ }
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 1b25427adf71..49328f1019c3 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -120,7 +120,20 @@ public class DisplayDeviceConfig {
// If no config can be loaded from any ddc xml at all,
// prepare a whole config using the global config.xml.
// Guaranteed not null
- if (isDefaultDisplay) {
+ return create(context, isDefaultDisplay);
+ }
+
+ /**
+ * Creates an instance using global values since no display device config xml exists.
+ * Uses values from config or PowerManager.
+ *
+ * @param context
+ * @param useConfigXml
+ * @return A configuration instance.
+ */
+ public static DisplayDeviceConfig create(Context context, boolean useConfigXml) {
+ DisplayDeviceConfig config;
+ if (useConfigXml) {
config = getConfigFromGlobalXml(context);
} else {
config = getConfigFromPmValues(context);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 6a229417316d..c62dd72ada70 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -249,30 +249,48 @@ public final class DisplayManagerService extends SystemService {
/** {@link DisplayBlanker} used by all {@link DisplayPowerController}s. */
private final DisplayBlanker mDisplayBlanker = new DisplayBlanker() {
+ // Synchronized to avoid race conditions when updating multiple display states.
@Override
- public void requestDisplayState(int displayId, int state, float brightness) {
- // TODO (b/168210494): Stop applying default display state to all displays.
- if (displayId != Display.DEFAULT_DISPLAY) {
- return;
- }
- final int[] displayIds;
+ public synchronized void requestDisplayState(int displayId, int state, float brightness) {
+ boolean allInactive = true;
+ boolean allOff = true;
+ final boolean stateChanged;
synchronized (mSyncRoot) {
- displayIds = mLogicalDisplayMapper.getDisplayIdsLocked();
+ final int index = mDisplayStates.indexOfKey(displayId);
+ if (index > -1) {
+ final int currentState = mDisplayStates.valueAt(index);
+ stateChanged = state != currentState;
+ if (stateChanged) {
+ final int size = mDisplayStates.size();
+ for (int i = 0; i < size; i++) {
+ final int displayState = i == index ? state : mDisplayStates.valueAt(i);
+ if (displayState != Display.STATE_OFF) {
+ allOff = false;
+ }
+ if (Display.isActiveState(displayState)) {
+ allInactive = false;
+ }
+ if (!allOff && !allInactive) {
+ break;
+ }
+ }
+ }
+ } else {
+ stateChanged = false;
+ }
}
// The order of operations is important for legacy reasons.
if (state == Display.STATE_OFF) {
- for (int id : displayIds) {
- requestDisplayStateInternal(id, state, brightness);
- }
+ requestDisplayStateInternal(displayId, state, brightness);
}
- mDisplayPowerCallbacks.onDisplayStateChange(state);
+ if (stateChanged) {
+ mDisplayPowerCallbacks.onDisplayStateChange(allInactive, allOff);
+ }
if (state != Display.STATE_OFF) {
- for (int id : displayIds) {
- requestDisplayStateInternal(id, state, brightness);
- }
+ requestDisplayStateInternal(displayId, state, brightness);
}
}
};
@@ -1160,7 +1178,7 @@ public final class DisplayManagerService extends SystemService {
private void handleLogicalDisplayRemovedLocked(@NonNull LogicalDisplay display) {
final int displayId = display.getDisplayIdLocked();
- mDisplayPowerControllers.delete(displayId);
+ mDisplayPowerControllers.removeReturnOld(displayId).stop();
mDisplayStates.delete(displayId);
mDisplayBrightnesses.delete(displayId);
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
@@ -2758,8 +2776,22 @@ public final class DisplayManagerService extends SystemService {
public boolean requestPowerState(int groupId, DisplayPowerRequest request,
boolean waitForNegativeProximity) {
synchronized (mSyncRoot) {
- return mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY)
- .requestPowerState(request, waitForNegativeProximity);
+ final DisplayGroup displayGroup = mLogicalDisplayMapper.getDisplayGroupLocked(
+ groupId);
+ if (displayGroup == null) {
+ return true;
+ }
+
+ final int size = displayGroup.getSizeLocked();
+ boolean ready = true;
+ for (int i = 0; i < size; i++) {
+ final DisplayPowerController displayPowerController =
+ mDisplayPowerControllers.get(displayGroup.getIdLocked(i));
+ ready &= displayPowerController.requestPowerState(request,
+ waitForNegativeProximity);
+ }
+
+ return ready;
}
}
@@ -2772,13 +2804,6 @@ public final class DisplayManagerService extends SystemService {
}
@Override
- public int getDisplayGroupId(int displayId) {
- synchronized (mSyncRoot) {
- return mLogicalDisplayMapper.getDisplayGroupIdLocked(displayId);
- }
- }
-
- @Override
public void registerDisplayGroupListener(DisplayGroupListener listener) {
mDisplayGroupListeners.add(listener);
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 9320f5027ce0..62cf86b31180 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -121,6 +121,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private static final int MSG_SET_TEMPORARY_BRIGHTNESS = 6;
private static final int MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT = 7;
private static final int MSG_IGNORE_PROXIMITY = 8;
+ private static final int MSG_STOP = 9;
private static final int PROXIMITY_UNKNOWN = -1;
private static final int PROXIMITY_NEGATIVE = 0;
@@ -351,6 +352,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
@Nullable
private final DisplayWhiteBalanceController mDisplayWhiteBalanceController;
+ @Nullable
private final ColorDisplayServiceInternal mCdsi;
private final float[] mNitsRange;
@@ -409,6 +411,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private ObjectAnimator mColorFadeOffAnimator;
private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
+ // True if this DisplayPowerController has been stopped and should no longer be running.
+ private boolean mStopped;
+
/**
* Creates the display power controller.
*/
@@ -583,14 +588,16 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
DisplayWhiteBalanceSettings displayWhiteBalanceSettings = null;
DisplayWhiteBalanceController displayWhiteBalanceController = null;
- try {
- displayWhiteBalanceSettings = new DisplayWhiteBalanceSettings(mContext, mHandler);
- displayWhiteBalanceController = DisplayWhiteBalanceFactory.create(mHandler,
- mSensorManager, resources);
- displayWhiteBalanceSettings.setCallbacks(this);
- displayWhiteBalanceController.setCallbacks(this);
- } catch (Exception e) {
- Slog.e(TAG, "failed to set up display white-balance: " + e);
+ if (mDisplayId == Display.DEFAULT_DISPLAY) {
+ try {
+ displayWhiteBalanceSettings = new DisplayWhiteBalanceSettings(mContext, mHandler);
+ displayWhiteBalanceController = DisplayWhiteBalanceFactory.create(mHandler,
+ mSensorManager, resources);
+ displayWhiteBalanceSettings.setCallbacks(this);
+ displayWhiteBalanceController.setCallbacks(this);
+ } catch (Exception e) {
+ Slog.e(TAG, "failed to set up display white-balance: " + e);
+ }
}
mDisplayWhiteBalanceSettings = displayWhiteBalanceSettings;
mDisplayWhiteBalanceController = displayWhiteBalanceController;
@@ -602,20 +609,24 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mNitsRange = BrightnessMappingStrategy.getFloatArray(context.getResources()
.obtainTypedArray(com.android.internal.R.array.config_screenBrightnessNits));
}
- mCdsi = LocalServices.getService(ColorDisplayServiceInternal.class);
- boolean active = mCdsi.setReduceBrightColorsListener(new ReduceBrightColorsListener() {
- @Override
- public void onReduceBrightColorsActivationChanged(boolean activated) {
- applyReduceBrightColorsSplineAdjustment();
- }
+ if (mDisplayId == Display.DEFAULT_DISPLAY) {
+ mCdsi = LocalServices.getService(ColorDisplayServiceInternal.class);
+ boolean active = mCdsi.setReduceBrightColorsListener(new ReduceBrightColorsListener() {
+ @Override
+ public void onReduceBrightColorsActivationChanged(boolean activated) {
+ applyReduceBrightColorsSplineAdjustment();
+ }
- @Override
- public void onReduceBrightColorsStrengthChanged(int strength) {
+ @Override
+ public void onReduceBrightColorsStrengthChanged(int strength) {
+ applyReduceBrightColorsSplineAdjustment();
+ }
+ });
+ if (active) {
applyReduceBrightColorsSplineAdjustment();
}
- });
- if (active) {
- applyReduceBrightColorsSplineAdjustment();
+ } else {
+ mCdsi = null;
}
}
@@ -713,6 +724,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
synchronized (mLock) {
+ if (mStopped) {
+ return true;
+ }
+
boolean changed = false;
if (waitForNegativeProximity
@@ -731,11 +746,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
if (changed) {
mDisplayReadyLocked = false;
- }
-
- if (changed && !mPendingRequestChangedLocked) {
- mPendingRequestChangedLocked = true;
- sendUpdatePowerStateLocked();
+ if (!mPendingRequestChangedLocked) {
+ mPendingRequestChangedLocked = true;
+ sendUpdatePowerStateLocked();
+ }
}
return mDisplayReadyLocked;
@@ -758,6 +772,34 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// TODO: b/175821789 - Support high brightness on multiple (folding) displays
}
+ /**
+ * Unregisters all listeners and interrupts all running threads; halting future work.
+ *
+ * This method should be called when the DisplayPowerController is no longer in use; i.e. when
+ * the {@link #mDisplayId display} has been removed.
+ */
+ public void stop() {
+ synchronized (mLock) {
+ mStopped = true;
+ Message msg = mHandler.obtainMessage(MSG_STOP);
+ mHandler.sendMessage(msg);
+
+ if (mDisplayWhiteBalanceController != null) {
+ mDisplayWhiteBalanceController.setEnabled(false);
+ }
+
+ if (mAutomaticBrightnessController != null) {
+ mAutomaticBrightnessController.stop();
+ }
+
+ if (mBrightnessTracker != null) {
+ mBrightnessTracker.stop();
+ }
+
+ mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
+ }
+ }
+
private void sendUpdatePowerState() {
synchronized (mLock) {
sendUpdatePowerStateLocked();
@@ -765,7 +807,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
private void sendUpdatePowerStateLocked() {
- if (!mPendingUpdatePowerStateLocked) {
+ if (!mStopped && !mPendingUpdatePowerStateLocked) {
mPendingUpdatePowerStateLocked = true;
Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
mHandler.sendMessage(msg);
@@ -788,7 +830,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mColorFadeOffAnimator.addListener(mAnimatorListener);
}
- mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
+ mScreenBrightnessRampAnimator = new RampAnimator<>(
mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS_FLOAT);
mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener);
@@ -829,12 +871,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
};
- private final RampAnimator.Listener mRampAnimatorListener = new RampAnimator.Listener() {
- @Override
- public void onAnimationEnd() {
- sendUpdatePowerState();
- }
- };
+ private final RampAnimator.Listener mRampAnimatorListener = this::sendUpdatePowerState;
+
+ /** Clean up all resources that are accessed via the {@link #mHandler} thread. */
+ private void cleanupHandlerThreadAfterStop() {
+ setProximitySensorEnabled(false);
+ mHandler.removeCallbacksAndMessages(null);
+ mPowerState.stop();
+ mPowerState = null;
+ }
private void updatePowerState() {
// Update the power state request.
@@ -844,6 +889,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
int brightnessAdjustmentFlags = 0;
mBrightnessReasonTemp.set(null);
synchronized (mLock) {
+ if (mStopped) {
+ return;
+ }
mPendingUpdatePowerStateLocked = false;
if (mPendingRequestLocked == null) {
return; // wait until first actual power request
@@ -2144,6 +2192,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
case MSG_IGNORE_PROXIMITY:
ignoreProximitySensorUntilChangedInternal();
break;
+
+ case MSG_STOP:
+ cleanupHandlerThreadAfterStop();
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 1d20d878fb81..77aff5b03dd2 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -72,6 +72,8 @@ final class DisplayPowerState {
private Runnable mCleanListener;
+ private volatile boolean mStopped;
+
DisplayPowerState(
DisplayBlanker blanker, ColorFade colorFade, int displayId, int displayState) {
mHandler = new Handler(true /*async*/);
@@ -264,9 +266,24 @@ final class DisplayPowerState {
}
}
+ /**
+ * Interrupts all running threads; halting future work.
+ *
+ * This method should be called when the DisplayPowerState is no longer in use; i.e. when
+ * the {@link #mDisplayId display} has been removed.
+ */
+ public void stop() {
+ mStopped = true;
+ mPhotonicModulator.interrupt();
+ dismissColorFade();
+ mCleanListener = null;
+ mHandler.removeCallbacksAndMessages(null);
+ }
+
public void dump(PrintWriter pw) {
pw.println();
pw.println("Display Power State:");
+ pw.println(" mStopped=" + mStopped);
pw.println(" mScreenState=" + Display.stateToString(mScreenState));
pw.println(" mScreenBrightness=" + mScreenBrightness);
pw.println(" mScreenReady=" + mScreenReady);
@@ -428,7 +445,11 @@ final class DisplayPowerState {
if (!stateChanged && !backlightChanged) {
try {
mLock.wait();
- } catch (InterruptedException ex) { }
+ } catch (InterruptedException ex) {
+ if (mStopped) {
+ return;
+ }
+ }
continue;
}
mActualState = state;
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 7ce4f066b058..5b2b3366b117 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -38,8 +38,8 @@ import android.view.DisplayEventReceiver;
import android.view.RoundedCorners;
import android.view.SurfaceControl;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.display.BrightnessSynchronizer;
-import com.android.internal.os.BackgroundThread;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.lights.LightsManager;
@@ -72,6 +72,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private final Injector mInjector;
+ private final SurfaceControlProxy mSurfaceControlProxy;
// Called with SyncRoot lock held.
public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
@@ -79,10 +80,12 @@ final class LocalDisplayAdapter extends DisplayAdapter {
this(syncRoot, context, handler, listener, new Injector());
}
+ @VisibleForTesting
LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener, Injector injector) {
super(syncRoot, context, handler, listener, TAG);
mInjector = injector;
+ mSurfaceControlProxy = mInjector.getSurfaceControlProxy();
}
@Override
@@ -92,22 +95,23 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInjector.setDisplayEventListenerLocked(getHandler().getLooper(),
new LocalDisplayEventListener());
- for (long physicalDisplayId : SurfaceControl.getPhysicalDisplayIds()) {
+ for (long physicalDisplayId : mSurfaceControlProxy.getPhysicalDisplayIds()) {
tryConnectDisplayLocked(physicalDisplayId);
}
}
private void tryConnectDisplayLocked(long physicalDisplayId) {
- final IBinder displayToken = SurfaceControl.getPhysicalDisplayToken(physicalDisplayId);
+ final IBinder displayToken =
+ mSurfaceControlProxy.getPhysicalDisplayToken(physicalDisplayId);
if (displayToken != null) {
SurfaceControl.StaticDisplayInfo staticInfo =
- SurfaceControl.getStaticDisplayInfo(displayToken);
+ mSurfaceControlProxy.getStaticDisplayInfo(displayToken);
if (staticInfo == null) {
Slog.w(TAG, "No valid static info found for display device " + physicalDisplayId);
return;
}
SurfaceControl.DynamicDisplayInfo dynamicInfo =
- SurfaceControl.getDynamicDisplayInfo(displayToken);
+ mSurfaceControlProxy.getDynamicDisplayInfo(displayToken);
if (dynamicInfo == null) {
Slog.w(TAG, "No valid dynamic info found for display device " + physicalDisplayId);
return;
@@ -131,7 +135,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
dynamicInfo.activeColorMode = Display.COLOR_MODE_INVALID;
}
SurfaceControl.DesiredDisplayModeSpecs modeSpecs =
- SurfaceControl.getDesiredDisplayModeSpecs(displayToken);
+ mSurfaceControlProxy.getDesiredDisplayModeSpecs(displayToken);
LocalDisplayDevice device = mDevices.get(physicalDisplayId);
if (device == null) {
// Display was added.
@@ -208,7 +212,6 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private SurfaceControl.DisplayMode mActiveSfDisplayMode;
private Spline mSystemBrightnessToNits;
private Spline mNitsToHalBrightness;
- private DisplayDeviceConfig mDisplayDeviceConfig;
private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides =
new DisplayEventReceiver.FrameRateOverride[0];
@@ -217,18 +220,15 @@ final class LocalDisplayAdapter extends DisplayAdapter {
SurfaceControl.StaticDisplayInfo staticDisplayInfo,
SurfaceControl.DynamicDisplayInfo dynamicInfo,
SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isDefaultDisplay) {
- super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId);
+ super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId,
+ getContext());
mPhysicalDisplayId = physicalDisplayId;
mIsDefaultDisplay = isDefaultDisplay;
updateDisplayPropertiesLocked(staticDisplayInfo, dynamicInfo, modeSpecs);
mSidekickInternal = LocalServices.getService(SidekickInternal.class);
- mBacklightAdapter = new BacklightAdapter(displayToken, isDefaultDisplay);
- mAllmSupported = SurfaceControl.getAutoLowLatencyModeSupport(displayToken);
- mGameContentTypeSupported = SurfaceControl.getGameContentTypeSupport(displayToken);
+ mBacklightAdapter = new BacklightAdapter(displayToken, isDefaultDisplay,
+ mSurfaceControlProxy);
mDisplayDeviceConfig = null;
- // Defer configuration file loading
- BackgroundThread.getHandler().sendMessage(PooledLambda.obtainMessage(
- LocalDisplayDevice::loadDisplayConfiguration, this));
}
@Override
@@ -248,6 +248,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
changed |= updateColorModesLocked(dynamicInfo.supportedColorModes,
dynamicInfo.activeColorMode);
changed |= updateHdrCapabilitiesLocked(dynamicInfo.hdrCapabilities);
+ changed |= updateAllmSupport(dynamicInfo.autoLowLatencyModeSupported);
+ changed |= updateGameContentTypeSupport(dynamicInfo.gameContentTypeSupported);
if (changed) {
mHavePendingChanges = true;
@@ -338,19 +340,18 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// If we can't map the defaultMode index to a mode, then the physical display
// modes must have changed, and the code below for handling changes to the
// list of available modes will take care of updating display mode specs.
- if (activeBaseMode != NO_DISPLAY_MODE_ID) {
- if (mDisplayModeSpecs.baseModeId != activeBaseMode
- || mDisplayModeSpecs.primaryRefreshRateRange.min
- != modeSpecs.primaryRefreshRateMin
- || mDisplayModeSpecs.primaryRefreshRateRange.max
- != modeSpecs.primaryRefreshRateMax
- || mDisplayModeSpecs.appRequestRefreshRateRange.min
- != modeSpecs.appRequestRefreshRateMin
- || mDisplayModeSpecs.appRequestRefreshRateRange.max
- != modeSpecs.appRequestRefreshRateMax) {
- mDisplayModeSpecsInvalid = true;
- sendTraversalRequestLocked();
- }
+ if (activeBaseMode == NO_DISPLAY_MODE_ID
+ || mDisplayModeSpecs.baseModeId != activeBaseMode
+ || mDisplayModeSpecs.primaryRefreshRateRange.min
+ != modeSpecs.primaryRefreshRateMin
+ || mDisplayModeSpecs.primaryRefreshRateRange.max
+ != modeSpecs.primaryRefreshRateMax
+ || mDisplayModeSpecs.appRequestRefreshRateRange.min
+ != modeSpecs.appRequestRefreshRateMin
+ || mDisplayModeSpecs.appRequestRefreshRateRange.max
+ != modeSpecs.appRequestRefreshRateMax) {
+ mDisplayModeSpecsInvalid = true;
+ sendTraversalRequestLocked();
}
}
@@ -408,6 +409,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
@Override
public DisplayDeviceConfig getDisplayDeviceConfig() {
+ if (mDisplayDeviceConfig == null) {
+ loadDisplayConfiguration();
+ }
return mDisplayDeviceConfig;
}
@@ -518,6 +522,22 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return true;
}
+ private boolean updateAllmSupport(boolean supported) {
+ if (mAllmSupported == supported) {
+ return false;
+ }
+ mAllmSupported = supported;
+ return true;
+ }
+
+ private boolean updateGameContentTypeSupport(boolean supported) {
+ if (mGameContentTypeSupported == supported) {
+ return false;
+ }
+ mGameContentTypeSupported = supported;
+ return true;
+ }
+
private SurfaceControl.DisplayMode getModeById(SurfaceControl.DisplayMode[] supportedModes,
int modeId) {
for (SurfaceControl.DisplayMode mode : supportedModes) {
@@ -698,7 +718,12 @@ final class LocalDisplayAdapter extends DisplayAdapter {
setDisplayState(Display.STATE_ON);
currentState = Display.STATE_ON;
} else {
- return; // old state and new state is off
+ if (oldState == Display.STATE_UNKNOWN) {
+ // There's no guarantee about what the initial state is
+ // at startup, so we have to set it if previous was UNKNOWN.
+ setDisplayState(state);
+ }
+ return;
}
}
@@ -757,7 +782,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
+ "id=" + physicalDisplayId
+ ", state=" + Display.stateToString(state) + ")");
try {
- SurfaceControl.setDisplayPowerMode(token, mode);
+ mSurfaceControlProxy.setDisplayPowerMode(token, mode);
Trace.traceCounter(Trace.TRACE_TAG_POWER, "DisplayPowerMode", mode);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
@@ -885,9 +910,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
// Do not lock when calling these SurfaceControl methods because they are sync
// operations that may block for a while when setting display power mode.
- SurfaceControl.setDesiredDisplayModeSpecs(displayToken, modeSpecs);
- final int sfActiveModeId =
- SurfaceControl.getDynamicDisplayInfo(displayToken).activeDisplayModeId;
+ mSurfaceControlProxy.setDesiredDisplayModeSpecs(displayToken, modeSpecs);
+
+ final int sfActiveModeId = mSurfaceControlProxy
+ .getDynamicDisplayInfo(displayToken).activeDisplayModeId;
synchronized (getSyncRoot()) {
if (updateActiveModeLocked(sfActiveModeId)) {
updateDeviceInfoLocked();
@@ -955,7 +981,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private void requestColorModeAsync(IBinder displayToken, int colorMode) {
// Do not lock when calling this SurfaceControl method because it is a sync operation
// that may block for a while when setting display power mode.
- SurfaceControl.setActiveColorMode(displayToken, colorMode);
+ mSurfaceControlProxy.setActiveColorMode(displayToken, colorMode);
synchronized (getSyncRoot()) {
updateDeviceInfoLocked();
}
@@ -975,7 +1001,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return;
}
- SurfaceControl.setAutoLowLatencyMode(getDisplayTokenLocked(), on);
+ mSurfaceControlProxy.setAutoLowLatencyMode(getDisplayTokenLocked(), on);
}
@Override
@@ -992,7 +1018,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return;
}
- SurfaceControl.setGameContentType(getDisplayTokenLocked(), on);
+ mSurfaceControlProxy.setGameContentType(getDisplayTokenLocked(), on);
}
@Override
@@ -1136,6 +1162,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
public void setDisplayEventListenerLocked(Looper looper, DisplayEventListener listener) {
mReceiver = new ProxyDisplayEventReceiver(looper, listener);
}
+ public SurfaceControlProxy getSurfaceControlProxy() {
+ return new SurfaceControlProxy();
+ }
}
public interface DisplayEventListener {
@@ -1227,10 +1256,65 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
+ @VisibleForTesting
+ static class SurfaceControlProxy {
+ public SurfaceControl.DynamicDisplayInfo getDynamicDisplayInfo(IBinder token) {
+ return SurfaceControl.getDynamicDisplayInfo(token);
+ }
+
+ public long[] getPhysicalDisplayIds() {
+ return SurfaceControl.getPhysicalDisplayIds();
+ }
+
+ public IBinder getPhysicalDisplayToken(long physicalDisplayId) {
+ return SurfaceControl.getPhysicalDisplayToken(physicalDisplayId);
+ }
+
+ public SurfaceControl.StaticDisplayInfo getStaticDisplayInfo(IBinder displayToken) {
+ return SurfaceControl.getStaticDisplayInfo(displayToken);
+ }
+
+ public SurfaceControl.DesiredDisplayModeSpecs getDesiredDisplayModeSpecs(
+ IBinder displayToken) {
+ return SurfaceControl.getDesiredDisplayModeSpecs(displayToken);
+ }
+
+ public boolean setDesiredDisplayModeSpecs(IBinder token,
+ SurfaceControl.DesiredDisplayModeSpecs specs) {
+ return SurfaceControl.setDesiredDisplayModeSpecs(token, specs);
+ }
+
+ public void setDisplayPowerMode(IBinder displayToken, int mode) {
+ SurfaceControl.setDisplayPowerMode(displayToken, mode);
+ }
+
+ public boolean setActiveColorMode(IBinder displayToken, int colorMode) {
+ return SurfaceControl.setActiveColorMode(displayToken, colorMode);
+ }
+
+ public void setAutoLowLatencyMode(IBinder displayToken, boolean on) {
+ SurfaceControl.setAutoLowLatencyMode(displayToken, on);
+
+ }
+
+ public void setGameContentType(IBinder displayToken, boolean on) {
+ SurfaceControl.setGameContentType(displayToken, on);
+ }
+
+ public boolean getDisplayBrightnessSupport(IBinder displayToken) {
+ return SurfaceControl.getDisplayBrightnessSupport(displayToken);
+ }
+
+ public boolean setDisplayBrightness(IBinder displayToken, float brightness) {
+ return SurfaceControl.setDisplayBrightness(displayToken, brightness);
+ }
+ }
+
static class BacklightAdapter {
private final IBinder mDisplayToken;
private final LogicalLight mBacklight;
private final boolean mUseSurfaceControlBrightness;
+ private final SurfaceControlProxy mSurfaceControlProxy;
private boolean mForceSurfaceControl = false;
@@ -1238,11 +1322,13 @@ final class LocalDisplayAdapter extends DisplayAdapter {
* @param displayToken Token for display associated with this backlight.
* @param isDefaultDisplay {@code true} if it is the default display.
*/
- BacklightAdapter(IBinder displayToken, boolean isDefaultDisplay) {
+ BacklightAdapter(IBinder displayToken, boolean isDefaultDisplay,
+ SurfaceControlProxy surfaceControlProxy) {
mDisplayToken = displayToken;
+ mSurfaceControlProxy = surfaceControlProxy;
- mUseSurfaceControlBrightness =
- SurfaceControl.getDisplayBrightnessSupport(mDisplayToken);
+ mUseSurfaceControlBrightness = mSurfaceControlProxy
+ .getDisplayBrightnessSupport(mDisplayToken);
if (!mUseSurfaceControlBrightness && isDefaultDisplay) {
LightsManager lights = LocalServices.getService(LightsManager.class);
@@ -1254,7 +1340,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
void setBrightness(float brightness) {
if (mUseSurfaceControlBrightness || mForceSurfaceControl) {
- SurfaceControl.setDisplayBrightness(mDisplayToken, brightness);
+ mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, brightness);
} else if (mBacklight != null) {
mBacklight.setBrightness(brightness);
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index a054db533e3f..a3ff534e336e 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -17,7 +17,6 @@
package com.android.server.display;
import android.content.Context;
-import android.os.Process;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.IndentingPrintWriter;
@@ -143,10 +142,6 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
return null;
}
- public int[] getDisplayIdsLocked() {
- return getDisplayIdsLocked(Process.SYSTEM_UID);
- }
-
public int[] getDisplayIdsLocked(int callingUid) {
final int count = mLogicalDisplays.size();
int[] displayIds = new int[count];
@@ -171,15 +166,6 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
}
}
- public int getDisplayGroupIdLocked(int displayId) {
- final DisplayGroup displayGroup = mDisplayIdToGroupMap.get(displayId);
- if (displayGroup != null) {
- return displayGroup.getGroupId();
- }
-
- return -1;
- }
-
public DisplayGroup getDisplayGroupLocked(int groupId) {
final int size = mDisplayIdToGroupMap.size();
for (int i = 0; i < size; i++) {
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 69943e3904ed..330379cf58eb 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -281,7 +281,8 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
List<OverlayMode> modes, int activeMode, int defaultMode,
float refreshRate, long presentationDeadlineNanos,
OverlayFlags flags, int state, SurfaceTexture surfaceTexture, int number) {
- super(OverlayDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + number);
+ super(OverlayDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + number,
+ getContext());
mName = name;
mRefreshRate = refreshRate;
mDisplayPresentationDeadlineNanos = presentationDeadlineNanos;
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index ff4717b7131b..52a810bd8caa 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -236,7 +236,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
int ownerUid, String ownerPackageName, Surface surface, int flags,
Callback callback, String uniqueId, int uniqueIndex,
VirtualDisplayConfig virtualDisplayConfig) {
- super(VirtualDisplayAdapter.this, displayToken, uniqueId);
+ super(VirtualDisplayAdapter.this, displayToken, uniqueId, getContext());
mAppToken = appToken;
mOwnerUid = ownerUid;
mOwnerPackageName = ownerPackageName;
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index 57323170b327..d2baaf2228a1 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -598,7 +598,8 @@ final class WifiDisplayAdapter extends DisplayAdapter {
public WifiDisplayDevice(IBinder displayToken, String name,
int width, int height, float refreshRate, int flags, String address,
Surface surface) {
- super(WifiDisplayAdapter.this, displayToken, DISPLAY_NAME_PREFIX + address);
+ super(WifiDisplayAdapter.this, displayToken, DISPLAY_NAME_PREFIX + address,
+ getContext());
mName = name;
mWidth = width;
mHeight = height;
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
index 86a8e36d748d..983b6b5bceb4 100644
--- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -100,9 +100,9 @@ final class DeviceSelectAction extends HdmiCecFeatureAction {
@Override
public boolean start() {
- if (mIsCec20) {
- sendSetStreamPath();
- }
+ // Wake-up on <Set Stream Path> was not mandatory before CEC 2.0.
+ // The message is re-sent at the end of the action for devices that don't support 2.0.
+ sendSetStreamPath();
int targetPowerStatus = localDevice().mService.getHdmiCecNetwork()
.getCecDeviceInfo(getTargetAddress()).getDevicePowerStatus();
if (!mIsCec20 || targetPowerStatus == HdmiControlManager.POWER_STATUS_UNKNOWN) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index f64efe7c26cc..624af30854dc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -39,6 +39,7 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ConcurrentUtils;
import com.android.server.hdmi.cec.config.CecSettings;
import com.android.server.hdmi.cec.config.Setting;
import com.android.server.hdmi.cec.config.Value;
@@ -55,7 +56,9 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Map.Entry;
import java.util.Set;
+import java.util.concurrent.Executor;
import javax.xml.datatype.DatatypeConfigurationException;
@@ -99,7 +102,7 @@ public class HdmiCecConfig {
private final Object mLock = new Object();
@GuardedBy("mLock")
- private final ArrayMap<Setting, Set<SettingChangeListener>>
+ private final ArrayMap<Setting, ArrayMap<SettingChangeListener, Executor>>
mSettingChangeListeners = new ArrayMap<>();
private SettingsObserver mSettingsObserver;
@@ -292,7 +295,7 @@ public class HdmiCecConfig {
case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED:
return STORAGE_GLOBAL_SETTINGS;
case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION:
- return STORAGE_GLOBAL_SETTINGS;
+ return STORAGE_SHARED_PREFS;
case HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE:
return STORAGE_GLOBAL_SETTINGS;
case HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE:
@@ -329,7 +332,7 @@ public class HdmiCecConfig {
case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED:
return Global.HDMI_CONTROL_ENABLED;
case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION:
- return Global.HDMI_CEC_VERSION;
+ return setting.getName();
case HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE:
return Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP;
case HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE:
@@ -402,9 +405,6 @@ public class HdmiCecConfig {
case Global.HDMI_CONTROL_ENABLED:
notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
break;
- case Global.HDMI_CEC_VERSION:
- notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION);
- break;
case Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP:
notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
break;
@@ -430,12 +430,20 @@ public class HdmiCecConfig {
private void notifySettingChanged(@NonNull Setting setting) {
synchronized (mLock) {
- Set<SettingChangeListener> listeners = mSettingChangeListeners.get(setting);
+ ArrayMap<SettingChangeListener, Executor> listeners =
+ mSettingChangeListeners.get(setting);
if (listeners == null) {
return; // No listeners registered, do nothing.
}
- for (SettingChangeListener listener: listeners) {
- listener.onChange(setting.getName());
+ for (Entry<SettingChangeListener, Executor> entry: listeners.entrySet()) {
+ SettingChangeListener listener = entry.getKey();
+ Executor executor = entry.getValue();
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ listener.onChange(setting.getName());
+ }
+ });
}
}
}
@@ -450,7 +458,6 @@ public class HdmiCecConfig {
ContentResolver resolver = mContext.getContentResolver();
String[] settings = new String[] {
Global.HDMI_CONTROL_ENABLED,
- Global.HDMI_CEC_VERSION,
Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED,
Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
@@ -471,10 +478,19 @@ public class HdmiCecConfig {
}
/**
- * Register change listener for a given setting name.
+ * Register change listener for a given setting name using DirectExecutor.
*/
public void registerChangeListener(@NonNull @CecSettingName String name,
SettingChangeListener listener) {
+ registerChangeListener(name, listener, ConcurrentUtils.DIRECT_EXECUTOR);
+ }
+
+ /**
+ * Register change listener for a given setting name and executor.
+ */
+ public void registerChangeListener(@NonNull @CecSettingName String name,
+ SettingChangeListener listener,
+ Executor executor) {
Setting setting = getSetting(name);
if (setting == null) {
throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
@@ -486,9 +502,9 @@ public class HdmiCecConfig {
}
synchronized (mLock) {
if (!mSettingChangeListeners.containsKey(setting)) {
- mSettingChangeListeners.put(setting, new HashSet<>());
+ mSettingChangeListeners.put(setting, new ArrayMap<>());
}
- mSettingChangeListeners.get(setting).add(listener);
+ mSettingChangeListeners.get(setting).put(listener, executor);
}
}
@@ -503,7 +519,8 @@ public class HdmiCecConfig {
}
synchronized (mLock) {
if (mSettingChangeListeners.containsKey(setting)) {
- Set<SettingChangeListener> listeners = mSettingChangeListeners.get(setting);
+ ArrayMap<SettingChangeListener, Executor> listeners =
+ mSettingChangeListeners.get(setting);
listeners.remove(listener);
if (listeners.isEmpty()) {
mSettingChangeListeners.remove(setting);
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index d014f149e831..b4d9b01f716f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -108,6 +108,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.Executor;
import java.util.stream.Collectors;
/**
@@ -199,6 +200,13 @@ public class HdmiControlService extends SystemService {
public @interface WakeReason {
}
+ private final Executor mServiceThreadExecutor = new Executor() {
+ @Override
+ public void execute(Runnable r) {
+ runOnServiceThread(r);
+ }
+ };
+
// Logical address of the active source.
@GuardedBy("mLock")
protected final ActiveSource mActiveSource = new ActiveSource();
@@ -520,14 +528,14 @@ public class HdmiControlService extends SystemService {
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
setControlEnabled(enabled);
}
- });
+ }, mServiceThreadExecutor);
mHdmiCecConfig.registerChangeListener(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
new HdmiCecConfig.SettingChangeListener() {
@Override
public void onChange(String setting) {
initializeCec(INITIATED_BY_ENABLE_CEC);
}
- });
+ }, mServiceThreadExecutor);
mHdmiCecConfig.registerChangeListener(
HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
new HdmiCecConfig.SettingChangeListener() {
@@ -537,7 +545,7 @@ public class HdmiControlService extends SystemService {
setCecOption(OptionKey.WAKEUP, tv().getAutoWakeup());
}
}
- });
+ }, mServiceThreadExecutor);
}
private void bootCompleted() {
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index a7f34ed85e0d..4c4c9783fab0 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -259,7 +259,7 @@ final class HotplugDetectionAction extends HdmiCecFeatureAction {
}
private void mayDisableSystemAudioAndARC(int address) {
- if (HdmiUtils.isEligibleAddressForDevice(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM, address)) {
+ if (!HdmiUtils.isEligibleAddressForDevice(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM, address)) {
return;
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index c5be20e39864..bbe52bcecea2 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.input;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -51,6 +52,8 @@ import android.hardware.input.InputManagerInternal.LidSwitchCallback;
import android.hardware.input.InputSensorInfo;
import android.hardware.input.KeyboardLayout;
import android.hardware.input.TouchCalibration;
+import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
import android.media.AudioManager;
import android.os.Binder;
import android.os.Bundle;
@@ -237,9 +240,21 @@ public class InputManagerService extends IInputManager.Stub
// List of vibrator states by device id.
@GuardedBy("mVibratorLock")
private final SparseBooleanArray mIsVibrating = new SparseBooleanArray();
+ private Object mLightLock = new Object();
+ // State for light tokens. A light token marks a lights manager session, it is generated
+ // by light session open() and deleted in session close().
+ // When lights session requests light states, the token will be used to find the light session.
+ @GuardedBy("mLightLock")
+ private final ArrayMap<IBinder, LightSession> mLightSessions =
+ new ArrayMap<IBinder, LightSession>();
// State for lid switch
+ // Lock for the lid switch state. Held when triggering callbacks to guarantee lid switch events
+ // are delivered in order. For ex, when a new lid switch callback is registered the lock is held
+ // while the callback is processing the initial lid switch event which guarantees that any
+ // events that occur at the same time are delivered after the callback has returned.
private final Object mLidSwitchLock = new Object();
+ @GuardedBy("mLidSwitchLock")
private List<LidSwitchCallback> mLidSwitchCallbacks = new ArrayList<>();
// State for the currently installed input filter.
@@ -303,6 +318,12 @@ public class InputManagerService extends IInputManager.Stub
private static native int[] nativeGetVibratorIds(long ptr, int deviceId);
private static native int nativeGetBatteryCapacity(long ptr, int deviceId);
private static native int nativeGetBatteryStatus(long ptr, int deviceId);
+ private static native List<Light> nativeGetLights(long ptr, int deviceId);
+ private static native int nativeGetLightPlayerId(long ptr, int deviceId, int lightId);
+ private static native int nativeGetLightColor(long ptr, int deviceId, int lightId);
+ private static native void nativeSetLightPlayerId(long ptr, int deviceId, int lightId,
+ int playerId);
+ private static native void nativeSetLightColor(long ptr, int deviceId, int lightId, int color);
private static native void nativeReloadKeyboardLayouts(long ptr);
private static native void nativeReloadDeviceAliases(long ptr);
private static native String nativeDump(long ptr);
@@ -387,9 +408,6 @@ 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;
- /** Indicates an open state for the lid switch. */
- public static final int SW_STATE_LID_OPEN = 0;
-
/** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
final boolean mUseDevInputEventForAudioJack;
@@ -425,13 +443,18 @@ public class InputManagerService extends IInputManager.Stub
}
void registerLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) {
- boolean lidOpen;
synchronized (mLidSwitchLock) {
mLidSwitchCallbacks.add(callback);
- lidOpen = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID)
- == SW_STATE_LID_OPEN;
+
+ // Skip triggering the initial callback if the system is not yet ready as the switch
+ // state will be reported as KEY_STATE_UNKNOWN. The callback will be triggered in
+ // systemRunning().
+ if (mSystemReady) {
+ boolean lidOpen = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID)
+ == KEY_STATE_UP;
+ callback.notifyLidSwitchChanged(0 /* whenNanos */, lidOpen);
+ }
}
- callback.notifyLidSwitchChanged(0 /* whenNanos */, lidOpen);
}
void unregisterLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) {
@@ -479,7 +502,18 @@ public class InputManagerService extends IInputManager.Stub
}
mNotificationManager = (NotificationManager)mContext.getSystemService(
Context.NOTIFICATION_SERVICE);
- mSystemReady = true;
+
+ synchronized (mLidSwitchLock) {
+ mSystemReady = true;
+
+ // Send the initial lid switch state to any callback registered before the system was
+ // ready.
+ int switchState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID);
+ for (int i = 0; i < mLidSwitchCallbacks.size(); i++) {
+ LidSwitchCallback callback = mLidSwitchCallbacks.get(i);
+ callback.notifyLidSwitchChanged(0 /* whenNanos */, switchState == KEY_STATE_UP);
+ }
+ }
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -2294,6 +2328,151 @@ public class InputManagerService extends IInputManager.Stub
}
}
+ /**
+ * LightSession represents a light session for lights manager.
+ */
+ private final class LightSession implements DeathRecipient {
+ private final int mDeviceId;
+ private final IBinder mToken;
+ private final String mOpPkg;
+ // The light ids and states that are requested by the light seesion
+ private int[] mLightIds;
+ private LightState[] mLightStates;
+
+ LightSession(int deviceId, String opPkg, IBinder token) {
+ mDeviceId = deviceId;
+ mOpPkg = opPkg;
+ mToken = token;
+ }
+
+ @Override
+ public void binderDied() {
+ if (DEBUG) {
+ Slog.d(TAG, "Light token died.");
+ }
+ synchronized (mLightLock) {
+ closeLightSession(mDeviceId, mToken);
+ mLightSessions.remove(mToken);
+ }
+ }
+ }
+
+ /**
+ * Returns the lights available for apps to control on the specified input device.
+ * Only lights that aren't reserved for system use are available to apps.
+ */
+ @Override // Binder call
+ public List<Light> getLights(int deviceId) {
+ return nativeGetLights(mPtr, deviceId);
+ }
+
+ /**
+ * Set specified light state with for a specific input device.
+ */
+ private void setLightStateInternal(int deviceId, Light light, LightState lightState) {
+ Preconditions.checkNotNull(light, "light does not exist");
+ if (DEBUG) {
+ Slog.d(TAG, "setLightStateInternal device " + deviceId + " light " + light
+ + "lightState " + lightState);
+ }
+ if (light.getType() == Light.LIGHT_TYPE_INPUT_PLAYER_ID) {
+ nativeSetLightPlayerId(mPtr, deviceId, light.getId(), lightState.getPlayerId());
+ } else if (light.getType() == Light.LIGHT_TYPE_INPUT_SINGLE
+ || light.getType() == Light.LIGHT_TYPE_INPUT_RGB) {
+ // Set ARGB format color to input device light
+ // Refer to https://developer.android.com/reference/kotlin/android/graphics/Color
+ nativeSetLightColor(mPtr, deviceId, light.getId(), lightState.getColor());
+ } else {
+ Slog.e(TAG, "setLightStates for unsupported light type " + light.getType());
+ }
+ }
+
+ /**
+ * Set multiple light states with multiple light ids for a specific input device.
+ */
+ private void setLightStatesInternal(int deviceId, int[] lightIds, LightState[] lightStates) {
+ final List<Light> lights = nativeGetLights(mPtr, deviceId);
+ SparseArray<Light> lightArray = new SparseArray<>();
+ for (int i = 0; i < lights.size(); i++) {
+ lightArray.put(lights.get(i).getId(), lights.get(i));
+ }
+ for (int i = 0; i < lightIds.length; i++) {
+ if (lightArray.contains(lightIds[i])) {
+ setLightStateInternal(deviceId, lightArray.get(lightIds[i]), lightStates[i]);
+ }
+ }
+ }
+
+ /**
+ * Set states for multiple lights for an opened light session.
+ */
+ @Override
+ public void setLightStates(int deviceId, int[] lightIds, LightState[] lightStates,
+ IBinder token) {
+ Preconditions.checkArgument(lightIds.length == lightStates.length,
+ "lights and light states are not same length");
+ synchronized (mLightLock) {
+ LightSession lightSession = mLightSessions.get(token);
+ Preconditions.checkArgument(lightSession != null, "not registered");
+ Preconditions.checkState(lightSession.mDeviceId == deviceId, "Incorrect device ID");
+ lightSession.mLightIds = lightIds.clone();
+ lightSession.mLightStates = lightStates.clone();
+ if (DEBUG) {
+ Slog.d(TAG, "setLightStates for " + lightSession.mOpPkg + " device " + deviceId);
+ }
+ }
+ setLightStatesInternal(deviceId, lightIds, lightStates);
+ }
+
+ @Override
+ public @Nullable LightState getLightState(int deviceId, int lightId) {
+ synchronized (mLightLock) {
+ int color = nativeGetLightColor(mPtr, deviceId, lightId);
+ int playerId = nativeGetLightPlayerId(mPtr, deviceId, lightId);
+
+ return new LightState(color, playerId);
+ }
+ }
+
+ @Override
+ public void openLightSession(int deviceId, String opPkg, IBinder token) {
+ Preconditions.checkNotNull(token);
+ synchronized (mLightLock) {
+ Preconditions.checkState(mLightSessions.get(token) == null, "already registered");
+ LightSession lightSession = new LightSession(deviceId, opPkg, token);
+ try {
+ token.linkToDeath(lightSession, 0);
+ } catch (RemoteException ex) {
+ // give up
+ ex.rethrowAsRuntimeException();
+ }
+ mLightSessions.put(token, lightSession);
+ if (DEBUG) {
+ Slog.d(TAG, "Open light session for " + opPkg + " device " + deviceId);
+ }
+ }
+ }
+
+ @Override
+ public void closeLightSession(int deviceId, IBinder token) {
+ Preconditions.checkNotNull(token);
+ synchronized (mLightLock) {
+ LightSession lightSession = mLightSessions.get(token);
+ Preconditions.checkState(lightSession != null, "not registered");
+ // Turn off the lights that were previously requested by the session to be closed.
+ Arrays.fill(lightSession.mLightStates, new LightState(0));
+ setLightStatesInternal(deviceId, lightSession.mLightIds,
+ lightSession.mLightStates);
+ mLightSessions.remove(token);
+ // If any other session is still pending with light request, apply the first session's
+ // request.
+ if (!mLightSessions.isEmpty()) {
+ LightSession nextSession = mLightSessions.valueAt(0);
+ setLightStatesInternal(deviceId, nextSession.mLightIds, nextSession.mLightStates);
+ }
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
@@ -2379,14 +2558,13 @@ public class InputManagerService extends IInputManager.Stub
if ((switchMask & SW_LID_BIT) != 0) {
final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
-
- ArrayList<LidSwitchCallback> callbacksCopy;
synchronized (mLidSwitchLock) {
- callbacksCopy = new ArrayList<>(mLidSwitchCallbacks);
- }
- for (int i = 0; i < callbacksCopy.size(); i++) {
- LidSwitchCallback callbacks = callbacksCopy.get(i);
- callbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
+ if (mSystemReady) {
+ for (int i = 0; i < mLidSwitchCallbacks.size(); i++) {
+ LidSwitchCallback callbacks = mLidSwitchCallbacks.get(i);
+ callbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/input/OWNERS b/services/core/java/com/android/server/input/OWNERS
index 0313a40f7270..82c6ee12c7ae 100644
--- a/services/core/java/com/android/server/input/OWNERS
+++ b/services/core/java/com/android/server/input/OWNERS
@@ -1,2 +1,3 @@
+lzye@google.com
michaelwr@google.com
svv@google.com
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 0754df0e6b9f..1e6658930840 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2620,8 +2620,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
// Dispatch display id for InputMethodService to update context display.
- executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
- MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
+ executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO(
+ MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken,
+ mMethodMap.get(mCurMethodId).getConfigChanges()));
scheduleNotifyImeUidToAudioService(mCurMethodUid);
if (mCurClient != null) {
clearClientSessionLocked(mCurClient);
@@ -4466,7 +4467,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
final IBinder token = (IBinder) args.arg2;
((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
- new InputMethodPrivilegedOperationsImpl(this, token));
+ new InputMethodPrivilegedOperationsImpl(this, token),
+ (int) args.arg3);
} catch (RemoteException e) {
}
args.recycle();
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index fd0b9454cfc1..cbbc981d9ed6 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -252,7 +252,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// @GuardedBy("mProviderManagers")
// hold lock for writes, no lock necessary for simple reads
- private final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers =
+ final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers =
new CopyOnWriteArrayList<>();
LocationManagerService(Context context, Injector injector, LocationEventLog eventLog) {
@@ -284,7 +284,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Nullable
- private LocationProviderManager getLocationProviderManager(String providerName) {
+ LocationProviderManager getLocationProviderManager(String providerName) {
if (providerName == null) {
return null;
}
@@ -496,7 +496,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public void startGnssBatch(long periodNanos, ILocationListener listener, String packageName,
- String attributionTag, String listenerId) {
+ @Nullable String attributionTag, String listenerId) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
if (mGnssManagerService == null) {
@@ -633,7 +633,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@Nullable
@Override
public ICancellationSignal getCurrentLocation(String provider, LocationRequest request,
- ILocationCallback consumer, String packageName, String attributionTag,
+ ILocationCallback consumer, String packageName, @Nullable String attributionTag,
String listenerId) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
listenerId);
@@ -657,7 +657,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public void registerLocationListener(String provider, LocationRequest request,
ILocationListener listener, String packageName, @Nullable String attributionTag,
- @Nullable String listenerId) {
+ String listenerId) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
listenerId);
int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
@@ -808,7 +808,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public Location getLastLocation(String provider, LastLocationRequest request,
- String packageName, String attributionTag) {
+ String packageName, @Nullable String attributionTag) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
identity.getPid());
@@ -875,9 +875,10 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public void registerGnssStatusCallback(IGnssStatusListener listener, String packageName,
- String attributionTag) {
+ @Nullable String attributionTag, String listenerId) {
if (mGnssManagerService != null) {
- mGnssManagerService.registerGnssStatusCallback(listener, packageName, attributionTag);
+ mGnssManagerService.registerGnssStatusCallback(listener, packageName, attributionTag,
+ listenerId);
}
}
@@ -890,9 +891,10 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public void registerGnssNmeaCallback(IGnssNmeaListener listener, String packageName,
- String attributionTag) {
+ @Nullable String attributionTag, String listenerId) {
if (mGnssManagerService != null) {
- mGnssManagerService.registerGnssNmeaCallback(listener, packageName, attributionTag);
+ mGnssManagerService.registerGnssNmeaCallback(listener, packageName, attributionTag,
+ listenerId);
}
}
@@ -904,11 +906,12 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public void addGnssMeasurementsListener(@Nullable GnssMeasurementRequest request,
- IGnssMeasurementsListener listener, String packageName, String attributionTag) {
+ public void addGnssMeasurementsListener(GnssMeasurementRequest request,
+ IGnssMeasurementsListener listener, String packageName, @Nullable String attributionTag,
+ String listenerId) {
if (mGnssManagerService != null) {
mGnssManagerService.addGnssMeasurementsListener(request, listener, packageName,
- attributionTag);
+ attributionTag, listenerId);
}
}
@@ -954,10 +957,10 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public void addGnssNavigationMessageListener(IGnssNavigationMessageListener listener,
- String packageName, String attributionTag) {
+ String packageName, @Nullable String attributionTag, String listenerId) {
if (mGnssManagerService != null) {
mGnssManagerService.addGnssNavigationMessageListener(listener, packageName,
- attributionTag);
+ attributionTag, listenerId);
}
}
@@ -1285,13 +1288,13 @@ public class LocationManagerService extends ILocationManager.Stub {
ipw.println("Historical Aggregate Location Provider Data:");
ipw.increaseIndent();
- ArrayMap<String, ArrayMap<String, LocationEventLog.AggregateStats>> aggregateStats =
+ ArrayMap<String, ArrayMap<CallerIdentity, LocationEventLog.AggregateStats>> aggregateStats =
mEventLog.copyAggregateStats();
for (int i = 0; i < aggregateStats.size(); i++) {
ipw.print(aggregateStats.keyAt(i));
ipw.println(":");
ipw.increaseIndent();
- ArrayMap<String, LocationEventLog.AggregateStats> providerStats =
+ ArrayMap<CallerIdentity, LocationEventLog.AggregateStats> providerStats =
aggregateStats.valueAt(i);
for (int j = 0; j < providerStats.size(); j++) {
ipw.print(providerStats.keyAt(j));
@@ -1359,7 +1362,7 @@ public class LocationManagerService extends ILocationManager.Stub {
if (provider != null && !provider.equals(manager.getName())) {
continue;
}
- if (identity.equalsIgnoringListenerId(manager.getIdentity())) {
+ if (identity.equals(manager.getIdentity())) {
return true;
}
}
diff --git a/services/core/java/com/android/server/location/countrydetector/ComprehensiveCountryDetector.java b/services/core/java/com/android/server/location/countrydetector/ComprehensiveCountryDetector.java
index af3907e78432..dda502b2b9aa 100644
--- a/services/core/java/com/android/server/location/countrydetector/ComprehensiveCountryDetector.java
+++ b/services/core/java/com/android/server/location/countrydetector/ComprehensiveCountryDetector.java
@@ -320,13 +320,15 @@ public class ComprehensiveCountryDetector extends CountryDetectorBase {
"(source: " + detectedCountry.getSource()
+ ", countryISO: " + detectedCountry.getCountryIso() + ")")
+ " isAirplaneModeOff()=" + isAirplaneModeOff()
+ + " isWifiOn()=" + isWifiOn()
+ " mListener=" + mListener
+ " isGeoCoderImplemnted()=" + isGeoCoderImplemented());
}
if (startLocationBasedDetection && (detectedCountry == null
|| detectedCountry.getSource() > Country.COUNTRY_SOURCE_LOCATION)
- && isAirplaneModeOff() && mListener != null && isGeoCoderImplemented()) {
+ && (isAirplaneModeOff() || isWifiOn()) && mListener != null
+ && isGeoCoderImplemented()) {
if (DEBUG) Slog.d(TAG, "run startLocationBasedDetector()");
// Start finding location when the source is less reliable than the
// location and the airplane mode is off (as geocoder will not
@@ -387,6 +389,11 @@ public class ComprehensiveCountryDetector extends CountryDetectorBase {
mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) == 0;
}
+ protected boolean isWifiOn() {
+ return Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.WIFI_ON, 0) != 0;
+ }
+
/**
* Notify the country change.
*/
diff --git a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
index dbfd0a52b013..29ce3783c4a1 100644
--- a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
+++ b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
@@ -64,16 +64,17 @@ public class LocationEventLog extends LocalEventLog {
private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 10;
@GuardedBy("mAggregateStats")
- private final ArrayMap<String, ArrayMap<String, AggregateStats>> mAggregateStats;
+ private final ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> mAggregateStats;
public LocationEventLog() {
super(getLogSize());
mAggregateStats = new ArrayMap<>(4);
}
- public ArrayMap<String, ArrayMap<String, AggregateStats>> copyAggregateStats() {
+ /** Copies out all aggregated stats. */
+ public ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> copyAggregateStats() {
synchronized (mAggregateStats) {
- ArrayMap<String, ArrayMap<String, AggregateStats>> copy = new ArrayMap<>(
+ ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> copy = new ArrayMap<>(
mAggregateStats);
for (int i = 0; i < copy.size(); i++) {
copy.setValueAt(i, new ArrayMap<>(copy.valueAt(i)));
@@ -82,17 +83,18 @@ public class LocationEventLog extends LocalEventLog {
}
}
- private AggregateStats getAggregateStats(String provider, String packageName) {
+ private AggregateStats getAggregateStats(String provider, CallerIdentity identity) {
synchronized (mAggregateStats) {
- ArrayMap<String, AggregateStats> packageMap = mAggregateStats.get(provider);
+ ArrayMap<CallerIdentity, AggregateStats> packageMap = mAggregateStats.get(provider);
if (packageMap == null) {
packageMap = new ArrayMap<>(2);
mAggregateStats.put(provider, packageMap);
}
- AggregateStats stats = packageMap.get(packageName);
+ CallerIdentity stripped = identity.stripListenerId();
+ AggregateStats stats = packageMap.get(stripped);
if (stats == null) {
stats = new AggregateStats();
- packageMap.put(packageName, stats);
+ packageMap.put(stripped, stats);
}
return stats;
}
@@ -117,34 +119,33 @@ public class LocationEventLog extends LocalEventLog {
public void logProviderClientRegistered(String provider, CallerIdentity identity,
LocationRequest request) {
addLogEvent(EVENT_PROVIDER_REGISTER_CLIENT, provider, identity, request);
- getAggregateStats(provider, identity.getPackageName())
- .markRequestAdded(request.getIntervalMillis());
+ getAggregateStats(provider, identity).markRequestAdded(request.getIntervalMillis());
}
/** Logs a client unregistration for a location provider. */
public void logProviderClientUnregistered(String provider, CallerIdentity identity) {
addLogEvent(EVENT_PROVIDER_UNREGISTER_CLIENT, provider, identity);
- getAggregateStats(provider, identity.getPackageName()).markRequestRemoved();
+ getAggregateStats(provider, identity).markRequestRemoved();
}
/** Logs a client for a location provider entering the active state. */
public void logProviderClientActive(String provider, CallerIdentity identity) {
- getAggregateStats(provider, identity.getPackageName()).markRequestActive();
+ getAggregateStats(provider, identity).markRequestActive();
}
/** Logs a client for a location provider leaving the active state. */
public void logProviderClientInactive(String provider, CallerIdentity identity) {
- getAggregateStats(provider, identity.getPackageName()).markRequestInactive();
+ getAggregateStats(provider, identity).markRequestInactive();
}
/** Logs a client for a location provider entering the foreground state. */
public void logProviderClientForeground(String provider, CallerIdentity identity) {
- getAggregateStats(provider, identity.getPackageName()).markRequestForeground();
+ getAggregateStats(provider, identity).markRequestForeground();
}
/** Logs a client for a location provider leaving the foreground state. */
public void logProviderClientBackground(String provider, CallerIdentity identity) {
- getAggregateStats(provider, identity.getPackageName()).markRequestBackground();
+ getAggregateStats(provider, identity).markRequestBackground();
}
/** Logs a change to the provider request for a location provider. */
@@ -165,7 +166,7 @@ public class LocationEventLog extends LocalEventLog {
if (Build.IS_DEBUGGABLE || D) {
addLogEvent(EVENT_PROVIDER_DELIVER_LOCATION, provider, numLocations, identity);
}
- getAggregateStats(provider, identity.getPackageName()).markLocationDelivered();
+ getAggregateStats(provider, identity).markLocationDelivered();
}
/** Logs that a provider has entered or exited stationary throttling. */
@@ -218,7 +219,7 @@ public class LocationEventLog extends LocalEventLog {
protected final String mProvider;
- protected ProviderEvent(long timeDelta, String provider) {
+ ProviderEvent(long timeDelta, String provider) {
super(timeDelta);
mProvider = provider;
}
@@ -234,7 +235,7 @@ public class LocationEventLog extends LocalEventLog {
private final int mUserId;
private final boolean mEnabled;
- protected ProviderEnabledEvent(long timeDelta, String provider, int userId,
+ ProviderEnabledEvent(long timeDelta, String provider, int userId,
boolean enabled) {
super(timeDelta, provider);
mUserId = userId;
@@ -252,7 +253,7 @@ public class LocationEventLog extends LocalEventLog {
private final boolean mMocked;
- protected ProviderMockedEvent(long timeDelta, String provider, boolean mocked) {
+ ProviderMockedEvent(long timeDelta, String provider, boolean mocked) {
super(timeDelta, provider);
mMocked = mocked;
}
@@ -273,7 +274,7 @@ public class LocationEventLog extends LocalEventLog {
private final CallerIdentity mIdentity;
@Nullable private final LocationRequest mLocationRequest;
- private ProviderRegisterEvent(long timeDelta, String provider, boolean registered,
+ ProviderRegisterEvent(long timeDelta, String provider, boolean registered,
CallerIdentity identity, @Nullable LocationRequest locationRequest) {
super(timeDelta, provider);
mRegistered = registered;
@@ -296,7 +297,7 @@ public class LocationEventLog extends LocalEventLog {
private final ProviderRequest mRequest;
- private ProviderUpdateEvent(long timeDelta, String provider, ProviderRequest request) {
+ ProviderUpdateEvent(long timeDelta, String provider, ProviderRequest request) {
super(timeDelta, provider);
mRequest = request;
}
@@ -311,7 +312,7 @@ public class LocationEventLog extends LocalEventLog {
private final int mNumLocations;
- private ProviderReceiveLocationEvent(long timeDelta, String provider, int numLocations) {
+ ProviderReceiveLocationEvent(long timeDelta, String provider, int numLocations) {
super(timeDelta, provider);
mNumLocations = numLocations;
}
@@ -327,7 +328,7 @@ public class LocationEventLog extends LocalEventLog {
private final int mNumLocations;
@Nullable private final CallerIdentity mIdentity;
- private ProviderDeliverLocationEvent(long timeDelta, String provider, int numLocations,
+ ProviderDeliverLocationEvent(long timeDelta, String provider, int numLocations,
@Nullable CallerIdentity identity) {
super(timeDelta, provider);
mNumLocations = numLocations;
@@ -345,7 +346,7 @@ public class LocationEventLog extends LocalEventLog {
private final boolean mStationaryThrottled;
- private ProviderStationaryThrottledEvent(long timeDelta, String provider,
+ ProviderStationaryThrottledEvent(long timeDelta, String provider,
boolean stationaryThrottled) {
super(timeDelta, provider);
mStationaryThrottled = stationaryThrottled;
@@ -363,7 +364,7 @@ public class LocationEventLog extends LocalEventLog {
@LocationPowerSaveMode
private final int mLocationPowerSaveMode;
- private LocationPowerSaveModeEvent(long timeDelta,
+ LocationPowerSaveModeEvent(long timeDelta,
@LocationPowerSaveMode int locationPowerSaveMode) {
super(timeDelta);
mLocationPowerSaveMode = locationPowerSaveMode;
@@ -401,7 +402,7 @@ public class LocationEventLog extends LocalEventLog {
private final int mUserId;
private final boolean mEnabled;
- private LocationEnabledEvent(long timeDelta, int userId, boolean enabled) {
+ LocationEnabledEvent(long timeDelta, int userId, boolean enabled) {
super(timeDelta);
mUserId = userId;
mEnabled = enabled;
diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
index b6695c20bd97..8312c6361835 100644
--- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java
+++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
@@ -60,7 +60,7 @@ public class GnssManagerService {
private static final String ATTRIBUTION_ID = "GnssService";
- private final Context mContext;
+ final Context mContext;
private final GnssNative mGnssNative;
private final GnssLocationProvider mGnssLocationProvider;
@@ -154,10 +154,11 @@ public class GnssManagerService {
* Registers listener for GNSS status changes.
*/
public void registerGnssStatusCallback(IGnssStatusListener listener, String packageName,
- @Nullable String attributionTag) {
+ @Nullable String attributionTag, String listenerId) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
- CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
+ listenerId);
mGnssStatusProvider.addListener(identity, listener);
}
@@ -172,10 +173,11 @@ public class GnssManagerService {
* Registers listener for GNSS NMEA messages.
*/
public void registerGnssNmeaCallback(IGnssNmeaListener listener, String packageName,
- @Nullable String attributionTag) {
+ @Nullable String attributionTag, String listenerId) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
- CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
+ listenerId);
mGnssNmeaProvider.addListener(identity, listener);
}
@@ -191,12 +193,13 @@ public class GnssManagerService {
*/
public void addGnssMeasurementsListener(GnssMeasurementRequest request,
IGnssMeasurementsListener listener, String packageName,
- @Nullable String attributionTag) {
+ @Nullable String attributionTag, String listenerId) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
if (request.isCorrelationVectorOutputsEnabled()) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
}
- CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
+ listenerId);
mGnssMeasurementsProvider.addListener(request, identity, listener);
}
@@ -223,10 +226,11 @@ public class GnssManagerService {
* Adds a GNSS navigation message listener.
*/
public void addGnssNavigationMessageListener(IGnssNavigationMessageListener listener,
- String packageName, @Nullable String attributionTag) {
+ String packageName, @Nullable String attributionTag, String listenerId) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
- CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
+ listenerId);
mGnssNavigationMessageProvider.addListener(identity, listener);
}
diff --git a/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java b/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
index 4e0a0b89f238..08deb8698608 100644
--- a/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
@@ -196,9 +196,12 @@ public abstract class AbstractLocationProvider {
*/
protected AbstractLocationProvider(Executor executor, @Nullable CallerIdentity identity,
@Nullable ProviderProperties properties) {
+ Preconditions.checkArgument(identity == null || identity.getListenerId() == null);
mExecutor = executor;
mInternalState = new AtomicReference<>(new InternalState(null,
- State.EMPTY_STATE.withIdentity(identity).withProperties(properties)));
+ State.EMPTY_STATE
+ .withIdentity(identity)
+ .withProperties(properties)));
mController = new Controller();
}
@@ -273,6 +276,7 @@ public abstract class AbstractLocationProvider {
* Call this method to report a change in provider packages.
*/
protected void setIdentity(@Nullable CallerIdentity identity) {
+ Preconditions.checkArgument(identity == null || identity.getListenerId() == null);
setState(state -> state.withIdentity(identity));
}
@@ -335,6 +339,8 @@ public abstract class AbstractLocationProvider {
private boolean mStarted = false;
+ Controller() {}
+
@Override
public State setListener(@Nullable Listener listener) {
InternalState oldInternalState = mInternalState.getAndUpdate(
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 388b5a4dd54e..5a35d7f88ff3 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -304,6 +304,7 @@ public class LocationProviderManager extends
LocationTransport transport, @PermissionLevel int permissionLevel) {
super(Objects.requireNonNull(request), identity, transport);
+ Preconditions.checkArgument(identity.getListenerId() != null);
Preconditions.checkArgument(permissionLevel > PERMISSION_NONE);
Preconditions.checkArgument(!request.getWorkSource().isEmpty());
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 30ea5556b41c..7e00fd69a148 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -194,7 +194,9 @@ class RebootEscrowManager {
}
public void reportMetric(boolean success) {
- FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, success);
+ // TODO(b/179105110) design error code; and report the true value for other fields.
+ FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, 0, 1, 1,
+ -1, 0);
}
public RebootEscrowEventLog getEventLog() {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 676f4218f745..4b4146683a09 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -29,6 +29,7 @@ import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.os.Process.INVALID_UID;
import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessCapability;
import android.net.NetworkPolicyManager;
import android.os.UserHandle;
import android.util.Log;
@@ -97,13 +98,15 @@ public class NetworkPolicyLogger {
}
}
- void uidStateChanged(int uid, int procState, long procStateSeq) {
+ void uidStateChanged(int uid, int procState, long procStateSeq,
+ @ProcessCapability int capability) {
synchronized (mLock) {
if (LOGV || uid == mDebugUid) {
Slog.v(TAG, uid + " state changed to "
- + ProcessList.makeProcStateString(procState) + " with seq=" + procStateSeq);
+ + ProcessList.makeProcStateString(procState) + ",seq=" + procStateSeq
+ + ",cap=" + ActivityManager.getCapabilitiesSummary(capability));
}
- mUidStateChangeBuffer.uidStateChanged(uid, procState, procStateSeq);
+ mUidStateChangeBuffer.uidStateChanged(uid, procState, procStateSeq, capability);
}
}
@@ -373,7 +376,8 @@ public class NetworkPolicyLogger {
super(Data.class, capacity);
}
- public void uidStateChanged(int uid, int procState, long procStateSeq) {
+ public void uidStateChanged(int uid, int procState, long procStateSeq,
+ @ProcessCapability int capability) {
final Data data = getNextSlot();
if (data == null) return;
@@ -381,6 +385,7 @@ public class NetworkPolicyLogger {
data.type = EVENT_UID_STATE_CHANGED;
data.ifield1 = uid;
data.ifield2 = procState;
+ data.ifield3 = capability;
data.lfield1 = procStateSeq;
data.timeStamp = System.currentTimeMillis();
}
@@ -546,8 +551,9 @@ public class NetworkPolicyLogger {
case EVENT_NETWORK_BLOCKED:
return data.ifield1 + "-" + getBlockedReason(data.ifield2);
case EVENT_UID_STATE_CHANGED:
- return data.ifield1 + "-" + ProcessList.makeProcStateString(data.ifield2)
- + "-" + data.lfield1;
+ return data.ifield1 + ":" + ProcessList.makeProcStateString(data.ifield2)
+ + ":" + ActivityManager.getCapabilitiesSummary(data.ifield3)
+ + ":" + data.lfield1;
case EVENT_POLICIES_CHANGED:
return getPolicyChangedLog(data.ifield1, data.ifield2, data.ifield3);
case EVENT_METEREDNESS_CHANGED:
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index aa7da54b2e1d..2b9dd2d84ac6 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -131,6 +131,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessCapability;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -166,6 +167,7 @@ import android.net.NetworkCapabilities;
import android.net.NetworkIdentity;
import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
+import android.net.NetworkPolicyManager.UidState;
import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
@@ -557,7 +559,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
/** Foreground at UID granularity. */
@GuardedBy("mUidRulesFirstLock")
- final SparseIntArray mUidState = new SparseIntArray();
+ final SparseArray<UidState> mUidState = new SparseArray<UidState>();
/** Map from network ID to last observed meteredness state */
@GuardedBy("mNetworkPoliciesSecondLock")
@@ -880,9 +882,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
try {
+ // TODO: There shouldn't be a need to receive callback for all changes.
mActivityManager.registerUidObserver(mUidObserver,
ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE,
- NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE, "android");
+ ActivityManager.PROCESS_STATE_UNKNOWN, "android");
mNetworkManager.registerObserver(mAlertObserver);
} catch (RemoteException e) {
// ignored; both services live in system_server
@@ -988,9 +991,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final private IUidObserver mUidObserver = new IUidObserver.Stub() {
@Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
- int capability) {
+ @ProcessCapability int capability) {
+ // TODO: Avoid creating a new UidStateCallbackInfo object every time
+ // we get a callback for an uid
mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED,
- uid, procState, procStateSeq).sendToTarget();
+ new UidStateCallbackInfo(uid, procState, procStateSeq, capability))
+ .sendToTarget();
}
@Override public void onUidGone(int uid, boolean disabled) {
@@ -1007,6 +1013,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
};
+ private static final class UidStateCallbackInfo {
+ public final int uid;
+ public final int procState;
+ public final long procStateSeq;
+ @ProcessCapability
+ public final int capability;
+
+ UidStateCallbackInfo(int uid, int procState, long procStateSeq,
+ @ProcessCapability int capability) {
+ this.uid = uid;
+ this.procState = procState;
+ this.procStateSeq = procStateSeq;
+ this.capability = capability;
+ }
+ }
+
final private BroadcastReceiver mPowerSaveWhitelistReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -3718,14 +3740,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
fout.print("UID=");
fout.print(uid);
- final int state = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
- fout.print(" state=");
- fout.print(state);
- if (state <= ActivityManager.PROCESS_STATE_TOP) {
- fout.print(" (fg)");
+ final UidState uidState = mUidState.get(uid);
+ if (uidState == null) {
+ fout.print(" state={null}");
} else {
- fout.print(state <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
- ? " (fg svc)" : " (bg)");
+ fout.print(" state=");
+ fout.print(uidState.toString());
}
final int uidRules = mUidRules.get(uid, RULE_NONE);
@@ -3783,26 +3803,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@VisibleForTesting
boolean isUidForeground(int uid) {
synchronized (mUidRulesFirstLock) {
- return isUidStateForeground(
- mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY));
+ return isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.get(uid));
}
}
@GuardedBy("mUidRulesFirstLock")
private boolean isUidForegroundOnRestrictBackgroundUL(int uid) {
- final int procState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
- return isProcStateAllowedWhileOnRestrictBackground(procState);
+ final UidState uidState = mUidState.get(uid);
+ return isProcStateAllowedWhileOnRestrictBackground(uidState);
}
@GuardedBy("mUidRulesFirstLock")
private boolean isUidForegroundOnRestrictPowerUL(int uid) {
- final int procState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
- return isProcStateAllowedWhileIdleOrPowerSaveMode(procState);
- }
-
- private boolean isUidStateForeground(int state) {
- // only really in foreground when screen is also on
- return state <= NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE;
+ final UidState uidState = mUidState.get(uid);
+ return isProcStateAllowedWhileIdleOrPowerSaveMode(uidState);
}
/**
@@ -3811,16 +3825,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* {@link #updateRulesForPowerRestrictionsUL(int)}. Returns true if the state was updated.
*/
@GuardedBy("mUidRulesFirstLock")
- private boolean updateUidStateUL(int uid, int uidState) {
+ private boolean updateUidStateUL(int uid, int procState, @ProcessCapability int capability) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateUidStateUL");
try {
- final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
- if (oldUidState != uidState) {
+ final UidState oldUidState = mUidState.get(uid);
+ if (oldUidState == null || oldUidState.procState != procState
+ || oldUidState.capability != capability) {
+ final UidState newUidState = new UidState(uid, procState, capability);
// state changed, push updated rules
- mUidState.put(uid, uidState);
- updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, uidState);
+ mUidState.put(uid, newUidState);
+ updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, newUidState);
if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
- != isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
+ != isProcStateAllowedWhileIdleOrPowerSaveMode(newUidState)) {
updateRuleForAppIdleUL(uid);
if (mDeviceIdleMode) {
updateRuleForDeviceIdleUL(uid);
@@ -3842,11 +3858,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private boolean removeUidStateUL(int uid) {
final int index = mUidState.indexOfKey(uid);
if (index >= 0) {
- final int oldUidState = mUidState.valueAt(index);
+ final UidState oldUidState = mUidState.valueAt(index);
mUidState.removeAt(index);
- if (oldUidState != ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
- updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState,
- ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+ if (oldUidState != null) {
+ updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, null);
if (mDeviceIdleMode) {
updateRuleForDeviceIdleUL(uid);
}
@@ -3873,8 +3888,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- private void updateRestrictBackgroundRulesOnUidStatusChangedUL(int uid, int oldUidState,
- int newUidState) {
+ private void updateRestrictBackgroundRulesOnUidStatusChangedUL(int uid,
+ @Nullable UidState oldUidState, @Nullable UidState newUidState) {
final boolean oldForeground =
isProcStateAllowedWhileOnRestrictBackground(oldUidState);
final boolean newForeground =
@@ -4979,11 +4994,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
public boolean handleMessage(Message msg) {
switch (msg.what) {
case UID_MSG_STATE_CHANGED: {
- final int uid = msg.arg1;
- final int procState = msg.arg2;
- final long procStateSeq = (Long) msg.obj;
-
- handleUidChanged(uid, procState, procStateSeq);
+ final UidStateCallbackInfo uidStateCallbackInfo =
+ (UidStateCallbackInfo) msg.obj;
+ final int uid = uidStateCallbackInfo.uid;
+ final int procState = uidStateCallbackInfo.procState;
+ final long procStateSeq = uidStateCallbackInfo.procStateSeq;
+ final int capability = uidStateCallbackInfo.capability;
+
+ handleUidChanged(uid, procState, procStateSeq, capability);
return true;
}
case UID_MSG_GONE: {
@@ -4998,23 +5016,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
};
- void handleUidChanged(int uid, int procState, long procStateSeq) {
+ void handleUidChanged(int uid, int procState, long procStateSeq,
+ @ProcessCapability int capability) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidStateChanged");
try {
boolean updated;
synchronized (mUidRulesFirstLock) {
// We received a uid state change callback, add it to the history so that it
// will be useful for debugging.
- mLogger.uidStateChanged(uid, procState, procStateSeq);
+ mLogger.uidStateChanged(uid, procState, procStateSeq, capability);
// Now update the network policy rules as per the updated uid state.
- updated = updateUidStateUL(uid, procState);
+ updated = updateUidStateUL(uid, procState, capability);
// Updating the network rules is done, so notify AMS about this.
mActivityManagerInternal.notifyNetworkPolicyRulesUpdated(uid, procStateSeq);
}
// Do this without the lock held. handleUidChanged() and handleUidGone() are
// called from the handler, so there's no multi-threading issue.
if (updated) {
- updateNetworkStats(uid, isUidStateForeground(procState));
+ updateNetworkStats(uid, isProcStateAllowedWhileOnRestrictBackground(procState));
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
@@ -5349,6 +5368,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ private static void collectKeys(SparseArray<UidState> source, SparseBooleanArray target) {
+ final int size = source.size();
+ for (int i = 0; i < size; i++) {
+ target.put(source.keyAt(i), true);
+ }
+ }
+
@Override
public void factoryReset(String subscriber) {
mContext.enforceCallingOrSelfPermission(NETWORK_SETTINGS, TAG);
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index 160d2daab6a2..afb47e831bdb 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -32,7 +32,7 @@ public interface NotificationDelegate {
void onNotificationActionClick(int callingUid, int callingPid, String key, int actionIndex,
Notification.Action action, NotificationVisibility nv, boolean generatedByAssistant);
void onNotificationClear(int callingUid, int callingPid,
- String pkg, String tag, int id, int userId, String key,
+ String pkg, int userId, String key,
@NotificationStats.DismissalSurface int dismissalSurface,
@NotificationStats.DismissalSentiment int dismissalSentiment,
NotificationVisibility nv);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8b4c6392fec0..f8cb2e4cecfc 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1044,15 +1044,19 @@ public class NotificationManagerService extends SystemService {
@Override
public void onNotificationClear(int callingUid, int callingPid,
- String pkg, String tag, int id, int userId, String key,
+ String pkg, int userId, String key,
@NotificationStats.DismissalSurface int dismissalSurface,
@NotificationStats.DismissalSentiment int dismissalSentiment,
NotificationVisibility nv) {
+ String tag = null;
+ int id = 0;
synchronized (mNotificationLock) {
NotificationRecord r = mNotificationsByKey.get(key);
if (r != null) {
r.recordDismissalSurface(dismissalSurface);
r.recordDismissalSentiment(dismissalSentiment);
+ tag = r.getSbn().getTag();
+ id = r.getSbn().getId();
}
}
cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index f078242a659f..4500bbcd250f 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -39,6 +39,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.util.XmlUtils;
+import com.android.server.pm.PackageManagerService;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -465,6 +466,7 @@ public class SnoozeHelper {
return PendingIntent.getBroadcast(mContext,
REQUEST_CODE_REPOST,
new Intent(REPOST_ACTION)
+ .setPackage(PackageManagerService.PLATFORM_PACKAGE_NAME)
.setData(new Uri.Builder().scheme(REPOST_SCHEME).appendPath(key).build())
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
.putExtra(EXTRA_KEY, key)
diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java
index d95a7254efe1..9c4c5101cb6c 100644
--- a/services/core/java/com/android/server/os/NativeTombstoneManager.java
+++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java
@@ -425,7 +425,7 @@ public final class NativeTombstoneManager {
}
}
stream.end(token);
-
+ break;
case (int) Tombstone.SELINUX_LABEL:
selinuxLabel = stream.readString(Tombstone.SELINUX_LABEL);
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 5d7c41c7b08f..1acbabda9e19 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -69,6 +69,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.Executor;
+import java.util.function.Function;
/**
* The entity responsible for filtering visibility between apps based on declarations in their
@@ -1354,14 +1355,13 @@ public class AppsFilter implements Watchable, Snappable {
}
public void dumpQueries(
- PrintWriter pw, PackageManagerService pms, @Nullable Integer filteringAppId,
- DumpState dumpState,
- int[] users) {
+ PrintWriter pw, @Nullable Integer filteringAppId, DumpState dumpState, int[] users,
+ Function<Integer, String[]> getPackagesForUid) {
final SparseArray<String> cache = new SparseArray<>();
ToString<Integer> expandPackages = input -> {
String cachedValue = cache.get(input);
if (cachedValue == null) {
- final String[] packagesForUid = pms.getPackagesForUid(input);
+ final String[] packagesForUid = getPackagesForUid.apply(input);
if (packagesForUid == null) {
cachedValue = "[unknown app id " + input + "]";
} else {
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
index 308e815d7659..9a9b14c31314 100644
--- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -171,7 +171,7 @@ public class DataLoaderManagerService extends SystemService {
}
}
- private class DataLoaderServiceConnection implements ServiceConnection {
+ private class DataLoaderServiceConnection implements ServiceConnection, IBinder.DeathRecipient {
final int mId;
final IDataLoaderStatusListener mListener;
IDataLoader mDataLoader;
@@ -194,6 +194,13 @@ public class DataLoaderManagerService extends SystemService {
mContext.unbindService(this);
return;
}
+ try {
+ service.linkToDeath(this, /*flags=*/0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to link to DataLoader's death: " + mId, e);
+ onBindingDied(className);
+ return;
+ }
callListener(IDataLoaderStatusListener.DATA_LOADER_BOUND);
}
@@ -218,6 +225,13 @@ public class DataLoaderManagerService extends SystemService {
destroy();
}
+ @Override
+ public void binderDied() {
+ Slog.i(TAG, "DataLoader " + mId + " died");
+ callListener(IDataLoaderStatusListener.DATA_LOADER_DESTROYED);
+ destroy();
+ }
+
IDataLoader getDataLoader() {
return mDataLoader;
}
diff --git a/services/core/java/com/android/server/pm/DumpState.java b/services/core/java/com/android/server/pm/DumpState.java
index 2a1fc87fc29f..380cdb10569b 100644
--- a/services/core/java/com/android/server/pm/DumpState.java
+++ b/services/core/java/com/android/server/pm/DumpState.java
@@ -55,6 +55,9 @@ public final class DumpState {
private int mOptions;
private boolean mTitlePrinted;
+ private boolean mFullPreferred;
+
+ private String mTargetPackageName;
private SharedUserSetting mSharedUser;
@@ -99,4 +102,20 @@ public final class DumpState {
public void setSharedUser(SharedUserSetting user) {
mSharedUser = user;
}
+
+ public String getTargetPackageName() {
+ return mTargetPackageName;
+ }
+
+ public void setTargetPackageName(String packageName) {
+ mTargetPackageName = packageName;
+ }
+
+ public boolean isFullPreferred() {
+ return mFullPreferred;
+ }
+
+ public void setFullPreferred(boolean fullPreferred) {
+ mFullPreferred = fullPreferred;
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index b9e3e0f4450b..0a443f3fd7f9 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -780,7 +780,8 @@ public class PackageDexOptimizer {
return getOatDir(codePath).getAbsolutePath();
}
- static File getOatDir(File codePath) {
+ /** Returns the oat dir for the given code path */
+ public static File getOatDir(File codePath) {
return new File(codePath, OAT_DIR_NAME);
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 9e2ca9d32315..7bf3c5c1f4c9 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1207,8 +1207,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock")
private void computeProgressLocked(boolean forcePublish) {
- mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
- + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
+ if (!mCommitted) {
+ mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
+ + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
+ } else {
+ // For incremental installs, continue publishing the install progress during committing.
+ mProgress = mIncrementalProgress;
+ }
// Only publish when meaningful change
if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
@@ -1944,9 +1949,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
"Session destroyed");
}
- // Client staging is fully done at this point
- mClientProgress = 1f;
- computeProgressLocked(true);
+ if (!isIncrementalInstallation()) {
+ // For non-incremental installs, client staging is fully done at this point
+ mClientProgress = 1f;
+ computeProgressLocked(true);
+ }
// This ongoing commit should keep session active, even though client
// will probably close their end.
@@ -3804,6 +3811,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
public void onPackageLoadingProgressChanged(float progress) {
synchronized (mLock) {
mIncrementalProgress = progress;
+ computeProgressLocked(true);
}
}
});
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2a3feb123dd9..16966d4de4e6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -369,6 +369,7 @@ import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.Settings.DatabaseVersion;
import com.android.server.pm.Settings.VersionInfo;
import com.android.server.pm.dex.ArtManagerService;
+import com.android.server.pm.dex.ArtUtils;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.PackageDexUsage;
@@ -1994,6 +1995,7 @@ public class PackageManagerService extends IPackageManager.Stub
SigningDetails getSigningDetails(int uid);
boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId);
boolean filterAppAccess(String packageName, int callingUid, int userId);
+ void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState);
}
/**
@@ -2037,6 +2039,9 @@ public class PackageManagerService extends IPackageManager.Stub
private final InstantAppResolverConnection mInstantAppResolverConnection;
private final DefaultAppProvider mDefaultAppProvider;
private final DomainVerificationManagerInternal mDomainVerificationManager;
+ private final PackageDexOptimizer mPackageDexOptimizer;
+ private final DexManager mDexManager;
+ private final CompilerStats mCompilerStats;
// PackageManagerService attributes that are primitives are referenced through the
// pms object directly. Primitives are the only attributes so referenced.
@@ -2083,6 +2088,9 @@ public class PackageManagerService extends IPackageManager.Stub
mInstantAppResolverConnection = args.service.mInstantAppResolverConnection;
mDefaultAppProvider = args.service.mDefaultAppProvider;
mDomainVerificationManager = args.service.mDomainVerificationManager;
+ mPackageDexOptimizer = args.service.mPackageDexOptimizer;
+ mDexManager = args.service.mDexManager;
+ mCompilerStats = args.service.mCompilerStats;
// Used to reference PMS attributes that are primitives and which are not
// updated under control of the PMS lock.
@@ -4393,6 +4401,143 @@ public class PackageManagerService extends IPackageManager.Stub
userId);
}
+ public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
+ final String packageName = dumpState.getTargetPackageName();
+
+ switch (type) {
+ case DumpState.DUMP_VERSION:
+ {
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
+ pw.println("Database versions:");
+ mSettings.dumpVersionLPr(new IndentingPrintWriter(pw, " "));
+ break;
+ }
+
+ case DumpState.DUMP_PREFERRED_XML:
+ {
+ pw.flush();
+ FileOutputStream fout = new FileOutputStream(fd);
+ BufferedOutputStream str = new BufferedOutputStream(fout);
+ TypedXmlSerializer serializer = Xml.newFastSerializer();
+ try {
+ serializer.setOutput(str, StandardCharsets.UTF_8.name());
+ serializer.startDocument(null, true);
+ serializer.setFeature(
+ "http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ mSettings.writePreferredActivitiesLPr(serializer, 0,
+ dumpState.isFullPreferred());
+ serializer.endDocument();
+ serializer.flush();
+ } catch (IllegalArgumentException e) {
+ pw.println("Failed writing: " + e);
+ } catch (IllegalStateException e) {
+ pw.println("Failed writing: " + e);
+ } catch (IOException e) {
+ pw.println("Failed writing: " + e);
+ }
+ break;
+ }
+
+ case DumpState.DUMP_QUERIES:
+ {
+ final PackageSetting setting = mSettings.getPackageLPr(packageName);
+ Integer filteringAppId = setting == null ? null : setting.appId;
+ mAppsFilter.dumpQueries(
+ pw, filteringAppId, dumpState, mUserManager.getUserIds(),
+ this::getPackagesForUid);
+ break;
+ }
+
+ case DumpState.DUMP_DOMAIN_PREFERRED:
+ {
+ final android.util.IndentingPrintWriter writer =
+ new android.util.IndentingPrintWriter(pw);
+ if (dumpState.onTitlePrinted()) pw.println();
+
+ writer.println("Domain verification status:");
+ writer.increaseIndent();
+ try {
+ mDomainVerificationManager.printState(writer, packageName,
+ UserHandle.USER_ALL, mSettings::getPackageLPr);
+ } catch (PackageManager.NameNotFoundException e) {
+ pw.println("Failure printing domain verification information");
+ Slog.e(TAG, "Failure printing domain verification information", e);
+ }
+ writer.decreaseIndent();
+ break;
+ }
+
+ case DumpState.DUMP_DEXOPT:
+ {
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ ipw.println();
+ ipw.println("Dexopt state:");
+ ipw.increaseIndent();
+ Collection<PackageSetting> pkgSettings;
+ if (packageName != null) {
+ PackageSetting targetPkgSetting = mSettings.getPackageLPr(packageName);
+ if (targetPkgSetting != null) {
+ pkgSettings = Collections.singletonList(targetPkgSetting);
+ } else {
+ ipw.println("Unable to find package: " + packageName);
+ return;
+ }
+ } else {
+ pkgSettings = mSettings.getPackagesLocked().values();
+ }
+
+ for (PackageSetting pkgSetting : pkgSettings) {
+ final AndroidPackage pkg = pkgSetting.getPkg();
+ if (pkg == null) {
+ continue;
+ }
+ ipw.println("[" + pkgSetting.name + "]");
+ ipw.increaseIndent();
+ mPackageDexOptimizer.dumpDexoptState(ipw, pkg, pkgSetting,
+ mDexManager.getPackageUseInfoOrDefault(pkg.getPackageName()));
+ ipw.decreaseIndent();
+ }
+ break;
+ }
+
+ case DumpState.DUMP_COMPILER_STATS:
+ {
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ ipw.println();
+ ipw.println("Compiler stats:");
+ ipw.increaseIndent();
+ Collection<AndroidPackage> packages;
+ if (packageName != null) {
+ AndroidPackage targetPackage = mPackages.get(packageName);
+ if (targetPackage != null) {
+ packages = Collections.singletonList(targetPackage);
+ } else {
+ ipw.println("Unable to find package: " + packageName);
+ return;
+ }
+ } else {
+ packages = mPackages.values();
+ }
+
+ for (AndroidPackage pkg : packages) {
+ final String pkgName = pkg.getPackageName();
+ ipw.println("[" + pkgName + "]");
+ ipw.increaseIndent();
+
+ CompilerStats.PackageStats stats = mCompilerStats.getPackageStats(pkgName);
+ if (stats == null) {
+ ipw.println("(No recorded stats)");
+ } else {
+ stats.dump(ipw);
+ }
+ ipw.decreaseIndent();
+ }
+ break;
+ }
+ } // switch
+ }
}
/**
@@ -23554,10 +23699,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
DumpState dumpState = new DumpState();
- boolean fullPreferred = false;
boolean checkin = false;
- String packageName = null;
ArraySet<String> permissionNames = null;
int opti = 0;
@@ -23626,7 +23769,7 @@ public class PackageManagerService extends IPackageManager.Stub
opti++;
// Is this a package name?
if ("android".equals(cmd) || cmd.contains(".")) {
- packageName = cmd;
+ dumpState.setTargetPackageName(cmd);
// When dumping a single package, we always dump all of its
// filter information since the amount of data will be reasonable.
dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS);
@@ -23707,7 +23850,7 @@ public class PackageManagerService extends IPackageManager.Stub
} else if ("preferred-xml".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_PREFERRED_XML);
if (opti < args.length && "--full".equals(args[opti])) {
- fullPreferred = true;
+ dumpState.setFullPreferred(true);
opti++;
}
} else if ("d".equals(cmd) || "domain-preferred-apps".equals(cmd)) {
@@ -23760,257 +23903,208 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ final String packageName = dumpState.getTargetPackageName();
if (checkin) {
pw.println("vers,1");
}
// reader
- synchronized (mLock) {
- if (dumpState.isDumping(DumpState.DUMP_VERSION) && packageName == null) {
- if (!checkin) {
- if (dumpState.onTitlePrinted())
- pw.println();
- pw.println("Database versions:");
- mSettings.dumpVersionLPr(new IndentingPrintWriter(pw, " "));
- }
+ if (dumpState.isDumping(DumpState.DUMP_VERSION) && packageName == null) {
+ if (!checkin) {
+ dump(DumpState.DUMP_VERSION, fd, pw, dumpState);
}
+ }
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_KNOWN_PACKAGES)
- && packageName == null) {
- if (dumpState.onTitlePrinted()) {
- pw.println();
- }
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
- ipw.println("Known Packages:");
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_KNOWN_PACKAGES)
+ && packageName == null) {
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ ipw.println("Known Packages:");
+ ipw.increaseIndent();
+ for (int i = 0; i <= LAST_KNOWN_PACKAGE; i++) {
+ final String knownPackage = mPmInternal.knownPackageToString(i);
+ ipw.print(knownPackage);
+ ipw.println(":");
+ final String[] pkgNames = mPmInternal.getKnownPackageNames(i,
+ UserHandle.USER_SYSTEM);
ipw.increaseIndent();
- for (int i = 0; i <= LAST_KNOWN_PACKAGE; i++) {
- final String knownPackage = mPmInternal.knownPackageToString(i);
- ipw.print(knownPackage);
- ipw.println(":");
- final String[] pkgNames = mPmInternal.getKnownPackageNames(i,
- UserHandle.USER_SYSTEM);
- ipw.increaseIndent();
- if (ArrayUtils.isEmpty(pkgNames)) {
- ipw.println("none");
- } else {
- for (String name : pkgNames) {
- ipw.println(name);
- }
+ if (ArrayUtils.isEmpty(pkgNames)) {
+ ipw.println("none");
+ } else {
+ for (String name : pkgNames) {
+ ipw.println(name);
}
- ipw.decreaseIndent();
}
ipw.decreaseIndent();
}
+ ipw.decreaseIndent();
+ }
+
+ if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) && packageName == null) {
+ final String requiredVerifierPackage = mRequiredVerifierPackage;
+ if (!checkin) {
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
+ pw.println("Verifiers:");
+ pw.print(" Required: ");
+ pw.print(requiredVerifierPackage);
+ pw.print(" (uid=");
+ pw.print(getPackageUid(requiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
+ UserHandle.USER_SYSTEM));
+ pw.println(")");
+ } else if (requiredVerifierPackage != null) {
+ pw.print("vrfy,"); pw.print(requiredVerifierPackage);
+ pw.print(",");
+ pw.println(getPackageUid(requiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
+ UserHandle.USER_SYSTEM));
+ }
+ }
- if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) && packageName == null) {
+ if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER) && packageName == null) {
+ final DomainVerificationProxy proxy = mDomainVerificationManager.getProxy();
+ final ComponentName verifierComponent = proxy.getComponentName();
+ if (verifierComponent != null) {
+ String verifierPackageName = verifierComponent.getPackageName();
if (!checkin) {
if (dumpState.onTitlePrinted())
pw.println();
- pw.println("Verifiers:");
- pw.print(" Required: ");
- pw.print(mRequiredVerifierPackage);
+ pw.println("Domain Verifier:");
+ pw.print(" Using: ");
+ pw.print(verifierPackageName);
pw.print(" (uid=");
- pw.print(getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
+ pw.print(getPackageUid(verifierPackageName, MATCH_DEBUG_TRIAGED_MISSING,
UserHandle.USER_SYSTEM));
pw.println(")");
- } else if (mRequiredVerifierPackage != null) {
- pw.print("vrfy,"); pw.print(mRequiredVerifierPackage);
+ } else if (verifierPackageName != null) {
+ pw.print("dv,"); pw.print(verifierPackageName);
pw.print(",");
- pw.println(getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
+ pw.println(getPackageUid(verifierPackageName, MATCH_DEBUG_TRIAGED_MISSING,
UserHandle.USER_SYSTEM));
}
+ } else {
+ pw.println();
+ pw.println("No Domain Verifier available!");
}
+ }
- if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER) &&
- packageName == null) {
- DomainVerificationProxy proxy = mDomainVerificationManager.getProxy();
- ComponentName verifierComponent = proxy.getComponentName();
- if (verifierComponent != null) {
- String verifierPackageName = verifierComponent.getPackageName();
- if (!checkin) {
- if (dumpState.onTitlePrinted())
- pw.println();
- pw.println("Domain Verifier:");
- pw.print(" Using: ");
- pw.print(verifierPackageName);
- pw.print(" (uid=");
- pw.print(getPackageUid(verifierPackageName, MATCH_DEBUG_TRIAGED_MISSING,
- UserHandle.USER_SYSTEM));
- pw.println(")");
- } else if (verifierPackageName != null) {
- pw.print("dv,"); pw.print(verifierPackageName);
- pw.print(",");
- pw.println(getPackageUid(verifierPackageName, MATCH_DEBUG_TRIAGED_MISSING,
- UserHandle.USER_SYSTEM));
- }
- } else {
- pw.println();
- pw.println("No Domain Verifier available!");
- }
+ if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) {
+ // TODO: Move it to ComputerEngine once LongSparseArray<SharedLibraryInfo> is copied
+ // in snapshot.
+ synchronized (mLock) {
+ dumpSharedLibrariesLPr(pw, dumpState, checkin);
}
+ }
- if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) {
- boolean printedHeader = false;
- final int numSharedLibraries = mSharedLibraries.size();
- for (int index = 0; index < numSharedLibraries; index++) {
- final String libName = mSharedLibraries.keyAt(index);
- WatchedLongSparseArray<SharedLibraryInfo> versionedLib
- = mSharedLibraries.get(libName);
- if (versionedLib == null) {
- continue;
- }
- final int versionCount = versionedLib.size();
- for (int i = 0; i < versionCount; i++) {
- SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
- if (!checkin) {
- if (!printedHeader) {
- if (dumpState.onTitlePrinted())
- pw.println();
- pw.println("Libraries:");
- printedHeader = true;
- }
- pw.print(" ");
- } else {
- pw.print("lib,");
- }
- pw.print(libraryInfo.getName());
- if (libraryInfo.isStatic()) {
- pw.print(" version=" + libraryInfo.getLongVersion());
- }
- if (!checkin) {
- pw.print(" -> ");
- }
- if (libraryInfo.getPath() != null) {
- if (libraryInfo.isNative()) {
- pw.print(" (so) ");
- } else {
- pw.print(" (jar) ");
- }
- pw.print(libraryInfo.getPath());
- } else {
- pw.print(" (apk) ");
- pw.print(libraryInfo.getPackageName());
- }
- pw.println();
- }
- }
+ if (dumpState.isDumping(DumpState.DUMP_FEATURES) && packageName == null) {
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
+ if (!checkin) {
+ pw.println("Features:");
}
- if (dumpState.isDumping(DumpState.DUMP_FEATURES) && packageName == null) {
- if (dumpState.onTitlePrinted())
- pw.println();
- if (!checkin) {
- pw.println("Features:");
- }
-
- synchronized (mAvailableFeatures) {
- for (FeatureInfo feat : mAvailableFeatures.values()) {
- if (checkin) {
- pw.print("feat,");
- pw.print(feat.name);
- pw.print(",");
- pw.println(feat.version);
- } else {
- pw.print(" ");
- pw.print(feat.name);
- if (feat.version > 0) {
- pw.print(" version=");
- pw.print(feat.version);
- }
- pw.println();
+ synchronized (mAvailableFeatures) {
+ for (FeatureInfo feat : mAvailableFeatures.values()) {
+ if (checkin) {
+ pw.print("feat,");
+ pw.print(feat.name);
+ pw.print(",");
+ pw.println(feat.version);
+ } else {
+ pw.print(" ");
+ pw.print(feat.name);
+ if (feat.version > 0) {
+ pw.print(" version=");
+ pw.print(feat.version);
}
+ pw.println();
}
}
}
+ }
- if (!checkin && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) {
+ synchronized (mLock) {
mComponentResolver.dumpActivityResolvers(pw, dumpState, packageName);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) {
+ }
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) {
+ synchronized (mLock) {
mComponentResolver.dumpReceiverResolvers(pw, dumpState, packageName);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) {
+ }
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) {
+ synchronized (mLock) {
mComponentResolver.dumpServiceResolvers(pw, dumpState, packageName);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) {
+ }
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) {
+ synchronized (mLock) {
mComponentResolver.dumpProviderResolvers(pw, dumpState, packageName);
}
+ }
- if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
+ // TODO: This cannot be moved to ComputerEngine since some variables with collections
+ // types in IntentResolver such as mTypeToFilter do not have a copy of `F[]`.
+ synchronized (mLock) {
mSettings.dumpPreferred(pw, dumpState, packageName);
}
+ }
- if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)) {
- pw.flush();
- FileOutputStream fout = new FileOutputStream(fd);
- BufferedOutputStream str = new BufferedOutputStream(fout);
- TypedXmlSerializer serializer = Xml.newFastSerializer();
- try {
- serializer.setOutput(str, StandardCharsets.UTF_8.name());
- serializer.startDocument(null, true);
- serializer.setFeature(
- "http://xmlpull.org/v1/doc/features.html#indent-output", true);
- mSettings.writePreferredActivitiesLPr(serializer, 0, fullPreferred);
- serializer.endDocument();
- serializer.flush();
- } catch (IllegalArgumentException e) {
- pw.println("Failed writing: " + e);
- } catch (IllegalStateException e) {
- pw.println("Failed writing: " + e);
- } catch (IOException e) {
- pw.println("Failed writing: " + e);
- }
- }
-
- if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
- android.util.IndentingPrintWriter writer =
- new android.util.IndentingPrintWriter(pw);
- if (dumpState.onTitlePrinted()) pw.println();
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)) {
+ dump(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState);
+ }
- writer.println("Domain verification status:");
- writer.increaseIndent();
- try {
- mDomainVerificationManager.printState(writer, packageName, UserHandle.USER_ALL,
- mSettings::getPackageLPr);
- } catch (PackageManager.NameNotFoundException e) {
- pw.println("Failure printing domain verification information");
- Slog.e(TAG, "Failure printing domain verification information", e);
- }
- writer.decreaseIndent();
- }
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
+ dump(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState);
+ }
- if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
- mSettings.dumpPermissionsLPr(pw, packageName, permissionNames, dumpState);
- }
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
+ mSettings.dumpPermissions(pw, packageName, permissionNames, dumpState);
+ }
- if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
+ synchronized (mLock) {
mComponentResolver.dumpContentProviders(pw, dumpState, packageName);
}
+ }
- if (!checkin && dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
+ synchronized (mLock) {
mSettings.getKeySetManagerService().dumpLPr(pw, packageName, dumpState);
}
+ }
- if (dumpState.isDumping(DumpState.DUMP_PACKAGES)) {
+ if (dumpState.isDumping(DumpState.DUMP_PACKAGES)) {
+ // This cannot be moved to ComputerEngine since some variables of the collections
+ // in PackageUserState such as suspendParams, disabledComponents and enabledComponents
+ // do not have a copy.
+ synchronized (mLock) {
mSettings.dumpPackagesLPr(pw, packageName, permissionNames, dumpState, checkin);
}
+ }
- if (dumpState.isDumping(DumpState.DUMP_QUERIES)) {
- final PackageSetting setting = mSettings.getPackageLPr(packageName);
- Integer filteringAppId = setting == null ? null : setting.appId;
- mAppsFilter.dumpQueries(
- pw, this, filteringAppId, dumpState,
- mUserManager.getUserIds());
- }
+ if (dumpState.isDumping(DumpState.DUMP_QUERIES)) {
+ dump(DumpState.DUMP_QUERIES, fd, pw, dumpState);
+ }
- if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) {
+ if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) {
+ // This cannot be moved to ComputerEngine since the set of packages in the
+ // SharedUserSetting do not have a copy.
+ synchronized (mLock) {
mSettings.dumpSharedUsersLPr(pw, packageName, permissionNames, dumpState, checkin);
}
+ }
- if (dumpState.isDumping(DumpState.DUMP_CHANGES)) {
- if (dumpState.onTitlePrinted()) pw.println();
- pw.println("Package Changes:");
+ if (dumpState.isDumping(DumpState.DUMP_CHANGES)) {
+ if (dumpState.onTitlePrinted()) pw.println();
+ pw.println("Package Changes:");
+ synchronized (mLock) {
pw.print(" Sequence number="); pw.println(mChangedPackagesSequenceNumber);
final int K = mChangedPackages.size();
for (int i = 0; i < K; i++) {
@@ -24032,16 +24126,18 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
}
+ }
- if (!checkin && dumpState.isDumping(DumpState.DUMP_FROZEN) && packageName == null) {
- // XXX should handle packageName != null by dumping only install data that
- // the given package is involved with.
- if (dumpState.onTitlePrinted()) pw.println();
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_FROZEN) && packageName == null) {
+ // XXX should handle packageName != null by dumping only install data that
+ // the given package is involved with.
+ if (dumpState.onTitlePrinted()) pw.println();
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
- ipw.println();
- ipw.println("Frozen packages:");
- ipw.increaseIndent();
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ ipw.println();
+ ipw.println("Frozen packages:");
+ ipw.increaseIndent();
+ synchronized (mLock) {
if (mFrozenPackages.size() == 0) {
ipw.println("(none)");
} else {
@@ -24049,16 +24145,18 @@ public class PackageManagerService extends IPackageManager.Stub
ipw.println(mFrozenPackages.valueAt(i));
}
}
- ipw.decreaseIndent();
}
+ ipw.decreaseIndent();
+ }
- if (!checkin && dumpState.isDumping(DumpState.DUMP_VOLUMES) && packageName == null) {
- if (dumpState.onTitlePrinted()) pw.println();
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_VOLUMES) && packageName == null) {
+ if (dumpState.onTitlePrinted()) pw.println();
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
- ipw.println();
- ipw.println("Loaded volumes:");
- ipw.increaseIndent();
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ ipw.println();
+ ipw.println("Loaded volumes:");
+ ipw.increaseIndent();
+ synchronized (mLoadedVolumes) {
if (mLoadedVolumes.size() == 0) {
ipw.println("(none)");
} else {
@@ -24066,36 +24164,39 @@ public class PackageManagerService extends IPackageManager.Stub
ipw.println(mLoadedVolumes.valueAt(i));
}
}
- ipw.decreaseIndent();
}
+ ipw.decreaseIndent();
+ }
- if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
- && packageName == null) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
+ && packageName == null) {
+ synchronized (mLock) {
mComponentResolver.dumpServicePermissions(pw, dumpState);
}
+ }
- if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) {
- if (dumpState.onTitlePrinted()) pw.println();
- dumpDexoptStateLPr(pw, packageName);
- }
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) {
+ if (dumpState.onTitlePrinted()) pw.println();
+ dump(DumpState.DUMP_DEXOPT, fd, pw, dumpState);
+ }
- if (!checkin && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) {
- if (dumpState.onTitlePrinted()) pw.println();
- dumpCompilerStatsLPr(pw, packageName);
- }
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) {
+ if (dumpState.onTitlePrinted()) pw.println();
+ dump(DumpState.DUMP_COMPILER_STATS, fd, pw, dumpState);
+ }
- if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
- if (dumpState.onTitlePrinted()) pw.println();
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
+ if (dumpState.onTitlePrinted()) pw.println();
+ synchronized (mLock) {
mSettings.dumpReadMessagesLPr(pw, dumpState);
-
- pw.println();
- pw.println("Package warning messages:");
- dumpCriticalInfo(pw, null);
}
+ pw.println();
+ pw.println("Package warning messages:");
+ dumpCriticalInfo(pw, null);
+ }
- if (checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES)) {
- dumpCriticalInfo(pw, "msg,");
- }
+ if (checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES)) {
+ dumpCriticalInfo(pw, "msg,");
}
// PackageInstaller should be called outside of mPackages lock
@@ -24130,6 +24231,14 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ /**
+ * Dump package manager states to the file according to a given dumping type of
+ * {@link DumpState}.
+ */
+ private void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
+ snapshotComputer().dump(type, fd, pw, dumpState);
+ }
+
//TODO: b/111402650
private void disableSkuSpecificApps() {
String apkList[] = mContext.getResources().getStringArray(
@@ -24228,69 +24337,50 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mLock")
- @SuppressWarnings("resource")
- private void dumpDexoptStateLPr(PrintWriter pw, String packageName) {
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
- ipw.println();
- ipw.println("Dexopt state:");
- ipw.increaseIndent();
- Collection<PackageSetting> pkgSettings;
- if (packageName != null) {
- PackageSetting targetPkgSetting = mSettings.getPackageLPr(packageName);
- if (targetPkgSetting != null) {
- pkgSettings = Collections.singletonList(targetPkgSetting);
- } else {
- ipw.println("Unable to find package: " + packageName);
- return;
- }
- } else {
- pkgSettings = mSettings.getPackagesLocked().values();
- }
-
- for (PackageSetting pkgSetting : pkgSettings) {
- if (pkgSetting.pkg == null) {
+ private void dumpSharedLibrariesLPr(PrintWriter pw, DumpState dumpState, boolean checkin) {
+ boolean printedHeader = false;
+ final int numSharedLibraries = mSharedLibraries.size();
+ for (int index = 0; index < numSharedLibraries; index++) {
+ final String libName = mSharedLibraries.keyAt(index);
+ WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(libName);
+ if (versionedLib == null) {
continue;
}
- ipw.println("[" + pkgSetting.name + "]");
- ipw.increaseIndent();
- mPackageDexOptimizer.dumpDexoptState(ipw, pkgSetting.pkg, pkgSetting,
- mDexManager.getPackageUseInfoOrDefault(pkgSetting.pkg.getPackageName()));
- ipw.decreaseIndent();
- }
- }
-
- @GuardedBy("mLock")
- @SuppressWarnings("resource")
- private void dumpCompilerStatsLPr(PrintWriter pw, String packageName) {
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
- ipw.println();
- ipw.println("Compiler stats:");
- ipw.increaseIndent();
- Collection<AndroidPackage> packages;
- if (packageName != null) {
- AndroidPackage targetPackage = mPackages.get(packageName);
- if (targetPackage != null) {
- packages = Collections.singletonList(targetPackage);
- } else {
- ipw.println("Unable to find package: " + packageName);
- return;
- }
- } else {
- packages = mPackages.values();
- }
-
- for (AndroidPackage pkg : packages) {
- ipw.println("[" + pkg.getPackageName() + "]");
- ipw.increaseIndent();
-
- CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.getPackageName());
- if (stats == null) {
- ipw.println("(No recorded stats)");
- } else {
- stats.dump(ipw);
+ final int versionCount = versionedLib.size();
+ for (int i = 0; i < versionCount; i++) {
+ SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
+ if (!checkin) {
+ if (!printedHeader) {
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
+ pw.println("Libraries:");
+ printedHeader = true;
+ }
+ pw.print(" ");
+ } else {
+ pw.print("lib,");
+ }
+ pw.print(libraryInfo.getName());
+ if (libraryInfo.isStatic()) {
+ pw.print(" version=" + libraryInfo.getLongVersion());
+ }
+ if (!checkin) {
+ pw.print(" -> ");
+ }
+ if (libraryInfo.getPath() != null) {
+ if (libraryInfo.isNative()) {
+ pw.print(" (so) ");
+ } else {
+ pw.print(" (jar) ");
+ }
+ pw.print(libraryInfo.getPath());
+ } else {
+ pw.print(" (apk) ");
+ pw.print(libraryInfo.getPackageName());
+ }
+ pw.println();
}
- ipw.decreaseIndent();
}
}
@@ -24452,7 +24542,9 @@ public class PackageManagerService extends IPackageManager.Stub
if (DEBUG_INSTALL) Slog.d(TAG, "Loaded packages " + loaded);
sendResourcesChangedBroadcast(true, false, loaded, null);
- mLoadedVolumes.add(vol.getId());
+ synchronized (mLoadedVolumes) {
+ mLoadedVolumes.add(vol.getId());
+ }
}
private void unloadPrivatePackages(final VolumeInfo vol) {
@@ -24500,7 +24592,9 @@ public class PackageManagerService extends IPackageManager.Stub
if (DEBUG_INSTALL) Slog.d(TAG, "Unloaded packages " + unloaded);
sendResourcesChangedBroadcast(false, false, unloaded, null);
- mLoadedVolumes.remove(vol.getId());
+ synchronized (mLoadedVolumes) {
+ mLoadedVolumes.remove(vol.getId());
+ }
// Try very hard to release any references to this path so we don't risk
// the system server being killed due to open FDs
@@ -27432,43 +27526,14 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private String getOatDir(AndroidPackage pkg, @NonNull PackageSetting pkgSetting) {
- if (!AndroidPackageUtils.canHaveOatDir(pkg,
- pkgSetting.getPkgState().isUpdatedSystemApp())) {
- return null;
- }
- File codePath = new File(pkg.getPath());
- if (codePath.isDirectory()) {
- return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath();
- }
- return null;
- }
-
void deleteOatArtifactsOfPackage(String packageName) {
- final String[] instructionSets;
- final List<String> codePaths;
- final String oatDir;
final AndroidPackage pkg;
final PackageSetting pkgSetting;
synchronized (mLock) {
pkg = mPackages.get(packageName);
pkgSetting = mSettings.getPackageLPr(packageName);
}
- instructionSets = getAppDexInstructionSets(
- AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting),
- AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting));
- codePaths = AndroidPackageUtils.getAllCodePaths(pkg);
- oatDir = getOatDir(pkg, pkgSetting);
-
- for (String codePath : codePaths) {
- for (String isa : instructionSets) {
- try {
- mInstaller.deleteOdex(codePath, isa, oatDir);
- } catch (InstallerException e) {
- Log.e(TAG, "Failed deleting oat files for " + codePath, e);
- }
- }
- }
+ mDexManager.deleteOptimizedFiles(ArtUtils.createArtPackageInfo(pkg, pkgSetting));
}
Set<String> getUnusedPackages(long downgradeTimeThresholdMillis) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 2112247650a5..ec7b451c6ec9 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -40,7 +40,6 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
import android.content.pm.IntentFilterVerificationInfo;
-import android.content.pm.overlay.OverlayPaths;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageUserState;
@@ -72,6 +71,7 @@ import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.incremental.IncrementalManager;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.service.pm.PackageServiceDumpProto;
@@ -1028,6 +1028,9 @@ public final class Settings implements Watchable, Snappable {
pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
}
pkgSetting.setPath(codePath);
+ if (IncrementalManager.isIncrementalPath(codePath.getAbsolutePath())) {
+ pkgSetting.incrementalStates = new IncrementalStates();
+ }
}
// If what we are scanning is a system (and possibly privileged) package,
// then make it so, regardless of whether it was previously installed only
@@ -4877,7 +4880,7 @@ public final class Settings implements Watchable, Snappable {
}
}
- void dumpPermissionsLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
+ void dumpPermissions(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
DumpState dumpState) {
LegacyPermissionSettings.dumpPermissions(pw, packageName, permissionNames,
mPermissionDataProvider.getLegacyPermissions(),
diff --git a/services/core/java/com/android/server/pm/dex/ArtPackageInfo.java b/services/core/java/com/android/server/pm/dex/ArtPackageInfo.java
new file mode 100644
index 000000000000..50bf916dceb3
--- /dev/null
+++ b/services/core/java/com/android/server/pm/dex/ArtPackageInfo.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.dex;
+
+import java.util.List;
+
+/**
+ * Holds package information relevant to ART use cases.
+ */
+public class ArtPackageInfo {
+ private final String mPackageName;
+ private final List<String> mInstructionSets;
+ private final List<String> mCodePaths;
+ // TODO: This should be computed on the fly in PackageDexOptimizer / DexManager, but the
+ // logic is too complicated to do it in a single re-factoring.
+ private final String mOatDir;
+
+ public ArtPackageInfo(
+ String packageName,
+ List<String> instructionSets,
+ List<String> codePaths,
+ String oatDir) {
+ mPackageName = packageName;
+ mInstructionSets = instructionSets;
+ mCodePaths = codePaths;
+ mOatDir = oatDir;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public List<String> getInstructionSets() {
+ return mInstructionSets;
+ }
+
+ public List<String> getCodePaths() {
+ return mCodePaths;
+ }
+
+ public String getOatDir() {
+ return mOatDir;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/dex/ArtUtils.java b/services/core/java/com/android/server/pm/dex/ArtUtils.java
new file mode 100644
index 000000000000..16d7a9a0afd8
--- /dev/null
+++ b/services/core/java/com/android/server/pm/dex/ArtUtils.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.dex;
+
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+
+import android.annotation.NonNull;
+
+import com.android.server.pm.PackageDexOptimizer;
+import com.android.server.pm.PackageSetting;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+
+import java.io.File;
+import java.util.Arrays;
+
+/**
+ * Utility class to interface between PM and ART tooling (e.g. DexManager).
+ */
+public final class ArtUtils {
+ private ArtUtils() {
+ }
+
+ /**
+ * Create the ART-representation of package info.
+ */
+ public static ArtPackageInfo createArtPackageInfo(
+ AndroidPackage pkg, PackageSetting pkgSetting) {
+ return new ArtPackageInfo(
+ pkg.getPackageName(),
+ Arrays.asList(getAppDexInstructionSets(
+ AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting),
+ AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting))),
+ AndroidPackageUtils.getAllCodePaths(pkg),
+ getOatDir(pkg, pkgSetting));
+ }
+
+ private static String getOatDir(AndroidPackage pkg, @NonNull PackageSetting pkgSetting) {
+ if (!AndroidPackageUtils.canHaveOatDir(pkg,
+ pkgSetting.getPkgState().isUpdatedSystemApp())) {
+ return null;
+ }
+ File codePath = new File(pkg.getPath());
+ if (codePath.isDirectory()) {
+ return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath();
+ }
+ return null;
+ }
+
+}
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index cc6d80a2aeec..349561d3f1d1 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -215,7 +215,7 @@ public class DexManager {
searchResult.mOutcome == DEX_SEARCH_FOUND_SPLIT;
if (primaryOrSplit && !isUsedByOtherApps
- && !PLATFORM_PACKAGE_NAME.equals(searchResult.mOwningPackageName)) {
+ && !isPlatformPackage(searchResult.mOwningPackageName)) {
// If the dex file is the primary apk (or a split) and not isUsedByOtherApps
// do not record it. This case does not bring any new usable information
// and can be safely skipped.
@@ -232,15 +232,24 @@ public class DexManager {
}
String classLoaderContext = mapping.getValue();
+
+ // Overwrite the class loader context for system server (instead of merging it).
+ // We expect system server jars to only change contexts in between OTAs and to
+ // otherwise be stable.
+ // Instead of implementing a complex clear-context logic post OTA, it is much
+ // simpler to always override the context for system server. This way, the context
+ // will always be up to date and we will avoid merging which could lead to the
+ // the context being marked as variable and thus making dexopt non-optimal.
+ boolean overwriteCLC = isPlatformPackage(searchResult.mOwningPackageName);
+
if (classLoaderContext != null
&& VMRuntime.isValidClassLoaderContext(classLoaderContext)) {
// Record dex file usage. If the current usage is a new pattern (e.g. new
// secondary, or UsedByOtherApps), record will return true and we trigger an
// async write to disk to make sure we don't loose the data in case of a reboot.
-
if (mPackageDexUsage.record(searchResult.mOwningPackageName,
dexPath, loaderUserId, loaderIsa, primaryOrSplit,
- loadingAppInfo.packageName, classLoaderContext)) {
+ loadingAppInfo.packageName, classLoaderContext, overwriteCLC)) {
mPackageDexUsage.maybeWriteAsync();
}
}
@@ -474,7 +483,7 @@ public class DexManager {
* because they don't need to be compiled)..
*/
public boolean dexoptSecondaryDex(DexoptOptions options) {
- if (PLATFORM_PACKAGE_NAME.equals(options.getPackageName())) {
+ if (isPlatformPackage(options.getPackageName())) {
// We could easily redirect to #dexoptSystemServer in this case. But there should be
// no-one calling this method directly for system server.
// As such we prefer to abort in this case.
@@ -534,7 +543,7 @@ public class DexManager {
* <p>PackageDexOptimizer.DEX_OPT_PERFORMED if all dexopt operations succeeded.
*/
public int dexoptSystemServer(DexoptOptions options) {
- if (!PLATFORM_PACKAGE_NAME.equals(options.getPackageName())) {
+ if (!isPlatformPackage(options.getPackageName())) {
Slog.wtf(TAG, "Non system server package used when trying to dexopt system server:"
+ options.getPackageName());
return PackageDexOptimizer.DEX_OPT_FAILED;
@@ -662,7 +671,7 @@ public class DexManager {
// Special handle system server files.
// We don't need an installd call because we have permissions to check if the file
// exists.
- if (PLATFORM_PACKAGE_NAME.equals(packageName)) {
+ if (isPlatformPackage(packageName)) {
if (!Files.exists(Paths.get(dexPath))) {
if (DEBUG) {
Slog.w(TAG, "A dex file previously loaded by System Server does not exist "
@@ -739,7 +748,8 @@ public class DexManager {
boolean newUpdate = mPackageDexUsage.record(searchResult.mOwningPackageName,
dexPath, userId, isa, /*primaryOrSplit*/ false,
loadingPackage,
- PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT);
+ PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT,
+ /*overwriteCLC*/ false);
update |= newUpdate;
}
if (update) {
@@ -809,7 +819,7 @@ public class DexManager {
// Note: We don't have any way to detect which code paths are actually
// owned by system server. We can only assume that such paths are on
// system partitions.
- if (PLATFORM_PACKAGE_NAME.equals(loadingAppInfo.packageName)) {
+ if (isPlatformPackage(loadingAppInfo.packageName)) {
if (isSystemServerDexPathSupportedForOdex(dexPath)) {
// We record system server dex files as secondary dex files.
// The reason is that we only record the class loader context for secondary dex
@@ -842,6 +852,11 @@ public class DexManager {
return new DexSearchResult(null, DEX_SEARCH_NOT_FOUND);
}
+ /** Returns true if this is the platform package .*/
+ private static boolean isPlatformPackage(String packageName) {
+ return PLATFORM_PACKAGE_NAME.equals(packageName);
+ }
+
private static <K,V> V putIfAbsent(Map<K,V> map, K key, V newValue) {
V existingValue = map.putIfAbsent(key, newValue);
return existingValue == null ? newValue : existingValue;
@@ -1000,6 +1015,22 @@ public class DexManager {
return isBtmCritical;
}
+ /**
+ * Deletes all the optimizations files generated by ART.
+ * @param packageInfo the package information.
+ */
+ public void deleteOptimizedFiles(ArtPackageInfo packageInfo) {
+ for (String codePath : packageInfo.getCodePaths()) {
+ for (String isa : packageInfo.getInstructionSets()) {
+ try {
+ mInstaller.deleteOdex(codePath, isa, packageInfo.getOatDir());
+ } catch (InstallerException e) {
+ Log.e(TAG, "Failed deleting oat files for " + codePath, e);
+ }
+ }
+ }
+ }
+
public static class RegisterDexModuleResult {
public RegisterDexModuleResult() {
this(false, null);
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
index 10760f52a02b..3d63b75c5da1 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -111,17 +111,18 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
* @param dexPath the path of the dex files being loaded
* @param ownerUserId the user id which runs the code loading the dex files
* @param loaderIsa the ISA of the app loading the dex files
- * @param isUsedByOtherApps whether or not this dex file was not loaded by its owning package
* @param primaryOrSplit whether or not the dex file is a primary/split dex. True indicates
* the file is either primary or a split. False indicates the file is secondary dex.
* @param loadingPackageName the package performing the load. Recorded only if it is different
* than {@param owningPackageName}.
+ * @param overwriteCLC if true, the class loader context will be overwritten instead of being
+ * merged
* @return true if the dex load constitutes new information, or false if this information
* has been seen before.
*/
/* package */ boolean record(String owningPackageName, String dexPath, int ownerUserId,
String loaderIsa, boolean primaryOrSplit,
- String loadingPackageName, String classLoaderContext) {
+ String loadingPackageName, String classLoaderContext, boolean overwriteCLC) {
if (!PackageManagerServiceUtils.checkISA(loaderIsa)) {
throw new IllegalArgumentException("loaderIsa " + loaderIsa + " is unsupported");
}
@@ -193,7 +194,7 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
}
// Merge the information into the existing data.
// Returns true if there was an update.
- return existingData.merge(newData) || updateLoadingPackages;
+ return existingData.merge(newData, overwriteCLC) || updateLoadingPackages;
}
}
}
@@ -809,14 +810,16 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
mLoadingPackages = new HashSet<>(other.mLoadingPackages);
}
- private boolean merge(DexUseInfo dexUseInfo) {
+ private boolean merge(DexUseInfo dexUseInfo, boolean overwriteCLC) {
boolean oldIsUsedByOtherApps = mIsUsedByOtherApps;
mIsUsedByOtherApps = mIsUsedByOtherApps || dexUseInfo.mIsUsedByOtherApps;
boolean updateIsas = mLoaderIsas.addAll(dexUseInfo.mLoaderIsas);
boolean updateLoadingPackages = mLoadingPackages.addAll(dexUseInfo.mLoadingPackages);
String oldClassLoaderContext = mClassLoaderContext;
- if (isUnsupportedContext(mClassLoaderContext)) {
+ if (overwriteCLC) {
+ mClassLoaderContext = dexUseInfo.mClassLoaderContext;
+ } else if (isUnsupportedContext(mClassLoaderContext)) {
mClassLoaderContext = dexUseInfo.mClassLoaderContext;
} else if (!Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
// We detected a context change.
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 71e53d9f1f40..7a936ec29498 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -68,15 +68,10 @@ import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManagerInternal;
-import android.app.role.RoleManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.PermissionGroupInfoFlags;
import android.content.pm.PackageManager.PermissionInfoFlags;
@@ -86,7 +81,6 @@ import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
-import android.content.pm.UserInfo;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.permission.SplitPermissionInfoParcelable;
@@ -401,105 +395,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
new PermissionManagerServiceInternalImpl();
LocalServices.addService(PermissionManagerServiceInternal.class, localService);
LocalServices.addService(PermissionManagerInternal.class, localService);
-
- context.getMainThreadHandler().post(() -> context.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (!Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
- return;
- }
-
- try {
- fixBgMicCamera(context);
- } catch (Throwable t) {
- // Don't crash the system if this fails for any reason. Any intermediate state
- // this can leave the permissions in is okay and in the worst case the state is
- // the same as before the user rebooted.
- Log.e(LOG_TAG, "Unable to fix background permissions", t);
- }
- }
-
-
- private void fixBgMicCamera(Context context) {
- PackageManager pm = context.getPackageManager();
- for (UserInfo userInfo : context.getSystemService(UserManager.class).getUsers()) {
- UserHandle user = userInfo.getUserHandle();
- List<String> assistants = context.getSystemService(RoleManager.class)
- .getRoleHoldersAsUser(RoleManager.ROLE_ASSISTANT, user);
- List<PackageInfo> packages =
- pm.getInstalledPackagesAsUser(PackageManager.MATCH_SYSTEM_ONLY
- | PackageManager.GET_PERMISSIONS, user.getIdentifier());
- for (PackageInfo packageInfo : packages) {
- String[] requestedPermissions = packageInfo.requestedPermissions;
- if (requestedPermissions == null) {
- continue;
- }
- for (String permName : requestedPermissions) {
- String pkg = packageInfo.packageName;
- switch (permName) {
- case Manifest.permission.BACKGROUND_CAMERA:
- removeFromAllowlistsAndRevoke(pm, pkg, permName, user);
- break;
- case Manifest.permission.RECORD_BACKGROUND_AUDIO:
- if (assistants.contains(pkg)) {
- removeFromAllowlistsAndRevokeForAssistant(pm, pkg, permName,
- user);
- } else {
- removeFromAllowlistsAndRevoke(pm, pkg, permName, user);
- }
- break;
- }
- }
- }
- }
- }
-
- private void removeFromAllowlistsAndRevoke(PackageManager pm, String pkg,
- String permName, UserHandle user) {
- if ((pm.getPermissionFlags(permName, pkg, user)
- & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0) {
- Slog.i(LOG_TAG, "removing " + pkg + " " + permName + " from all allowlists");
- pm.removeWhitelistedRestrictedPermission(pkg, permName,
- FLAG_PERMISSION_WHITELIST_UPGRADE);
- pm.removeWhitelistedRestrictedPermission(pkg, permName,
- FLAG_PERMISSION_WHITELIST_SYSTEM);
- pm.removeWhitelistedRestrictedPermission(pkg, permName,
- FLAG_PERMISSION_WHITELIST_INSTALLER);
- pm.removeWhitelistedRestrictedPermission(pkg, permName,
- FLAG_PERMISSION_ALLOWLIST_ROLE);
- }
- if (pm.checkPermission(permName, pkg) == PackageManager.PERMISSION_GRANTED) {
- Slog.i(LOG_TAG, "revoking " + pkg + " " + permName);
- pm.revokeRuntimePermission(pkg, permName, user);
- }
- }
-
- private void removeFromAllowlistsAndRevokeForAssistant(PackageManager pm, String pkg,
- String permName, UserHandle user) {
- int anyNonRoleExempt =
- FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT
- | FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
- | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
-
- if ((pm.getPermissionFlags(permName, pkg, user) & anyNonRoleExempt) != 0) {
- Slog.i(LOG_TAG, "removing " + pkg + " " + permName
- + " from all allowlists except role");
- pm.removeWhitelistedRestrictedPermission(pkg, permName,
- FLAG_PERMISSION_WHITELIST_UPGRADE);
- pm.removeWhitelistedRestrictedPermission(pkg, permName,
- FLAG_PERMISSION_WHITELIST_SYSTEM);
- pm.removeWhitelistedRestrictedPermission(pkg, permName,
- FLAG_PERMISSION_WHITELIST_INSTALLER);
- }
- if ((pm.getPermissionFlags(permName, pkg, user)
- & FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT) == 0) {
- Slog.i(LOG_TAG, "adding " + pkg + " " + permName
- + " to role allowlist");
- pm.addWhitelistedRestrictedPermission(pkg, permName,
- FLAG_PERMISSION_ALLOWLIST_ROLE);
- }
- }
- }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)));
}
@Override
diff --git a/services/core/java/com/android/server/power/DisplayGroupPowerStateMapper.java b/services/core/java/com/android/server/power/DisplayGroupPowerStateMapper.java
new file mode 100644
index 000000000000..2fcd178c3d15
--- /dev/null
+++ b/services/core/java/com/android/server/power/DisplayGroupPowerStateMapper.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
+import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
+
+import static com.android.server.power.DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener.DISPLAY_GROUP_ADDED;
+import static com.android.server.power.DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener.DISPLAY_GROUP_CHANGED;
+import static com.android.server.power.DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener.DISPLAY_GROUP_REMOVED;
+
+import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.os.PowerManagerInternal;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.Display;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.display.DisplayGroup;
+
+/**
+ * Responsible for creating {@link DisplayPowerRequest}s and associating them with
+ * {@link com.android.server.display.DisplayGroup}s.
+ *
+ * Each {@link com.android.server.display.DisplayGroup} has a single {@link DisplayPowerRequest}
+ * which is used to request power state changes to every display in the group.
+ */
+public class DisplayGroupPowerStateMapper {
+
+ private static final String TAG = "DisplayPowerRequestMapper";
+
+ /** Lock obtained from {@link PowerManagerService}. */
+ private final Object mLock;
+
+ /** Listener to inform of changes to display groups. */
+ private final DisplayGroupPowerChangeListener mListener;
+
+ /** A mapping from DisplayGroup Id to DisplayGroup information. */
+ @GuardedBy("mLock")
+ private final SparseArray<DisplayGroupInfo> mDisplayGroupInfos = new SparseArray<>();
+
+ /** A cached array of DisplayGroup Ids. */
+ @GuardedBy("mLock")
+ private int[] mDisplayGroupIds;
+
+ private final DisplayManagerInternal.DisplayGroupListener mDisplayGroupListener =
+ new DisplayManagerInternal.DisplayGroupListener() {
+ @Override
+ public void onDisplayGroupAdded(int groupId) {
+ synchronized (mLock) {
+ if (mDisplayGroupInfos.contains(groupId)) {
+ Slog.e(TAG, "Tried to add already existing group:" + groupId);
+ return;
+ }
+ // For now, only the default group supports sandman (dream/AOD).
+ final boolean supportsSandman = groupId == Display.DEFAULT_DISPLAY_GROUP;
+ final DisplayGroupInfo displayGroupInfo = new DisplayGroupInfo(
+ new DisplayPowerRequest(),
+ getGlobalWakefulnessLocked(),
+ /* ready= */ false,
+ supportsSandman);
+ mDisplayGroupInfos.append(groupId, displayGroupInfo);
+ mDisplayGroupIds = ArrayUtils.appendInt(mDisplayGroupIds, groupId);
+ mListener.onDisplayGroupEventLocked(DISPLAY_GROUP_ADDED, groupId);
+ }
+ }
+
+ @Override
+ public void onDisplayGroupRemoved(int groupId) {
+ synchronized (mLock) {
+ if (!mDisplayGroupInfos.contains(groupId)) {
+ Slog.e(TAG, "Tried to remove non-existent group:" + groupId);
+ return;
+ }
+ mDisplayGroupInfos.delete(groupId);
+ mDisplayGroupIds = ArrayUtils.removeInt(mDisplayGroupIds, groupId);
+ mListener.onDisplayGroupEventLocked(DISPLAY_GROUP_REMOVED, groupId);
+ }
+ }
+
+ @Override
+ public void onDisplayGroupChanged(int groupId) {
+ synchronized (mLock) {
+ mListener.onDisplayGroupEventLocked(DISPLAY_GROUP_CHANGED, groupId);
+ }
+ }
+ };
+
+ DisplayGroupPowerStateMapper(Object lock, DisplayManagerInternal displayManagerInternal,
+ DisplayGroupPowerChangeListener listener) {
+ mLock = lock;
+ mListener = listener;
+ displayManagerInternal.registerDisplayGroupListener(mDisplayGroupListener);
+
+ final DisplayGroupInfo displayGroupInfo = new DisplayGroupInfo(
+ new DisplayPowerRequest(), WAKEFULNESS_AWAKE, /* ready= */
+ false, /* supportsSandman= */ true);
+ mDisplayGroupInfos.append(Display.DEFAULT_DISPLAY_GROUP, displayGroupInfo);
+ mDisplayGroupIds = new int[]{Display.DEFAULT_DISPLAY_GROUP};
+ }
+
+ DisplayPowerRequest getPowerRequestLocked(int groupId) {
+ return mDisplayGroupInfos.get(groupId).displayPowerRequest;
+ }
+
+ int[] getDisplayGroupIdsLocked() {
+ return mDisplayGroupIds;
+ }
+
+ int getWakefulnessLocked(int groupId) {
+ return mDisplayGroupInfos.get(groupId).wakefulness;
+ }
+
+ void setLastPowerOnTimeLocked(int groupId, long eventTime) {
+ mDisplayGroupInfos.get(groupId).lastPowerOnTime = eventTime;
+ }
+
+ long getLastPowerOnTimeLocked(int groupId) {
+ return mDisplayGroupInfos.get(groupId).lastPowerOnTime;
+ }
+
+ /**
+ * Returns the amalgamated wakefulness of all {@link DisplayGroup DisplayGroups}.
+ *
+ * <p>This will be the highest wakeful state of all {@link DisplayGroup DisplayGroups}; ordered
+ * from highest to lowest:
+ * <ol>
+ * <li>{@link PowerManagerInternal#WAKEFULNESS_AWAKE}
+ * <li>{@link PowerManagerInternal#WAKEFULNESS_DREAMING}
+ * <li>{@link PowerManagerInternal#WAKEFULNESS_DOZING}
+ * <li>{@link PowerManagerInternal#WAKEFULNESS_ASLEEP}
+ * </ol>
+ */
+ int getGlobalWakefulnessLocked() {
+ final int size = mDisplayGroupInfos.size();
+ int deviceWakefulness = WAKEFULNESS_ASLEEP;
+ for (int i = 0; i < size; i++) {
+ final int wakefulness = mDisplayGroupInfos.valueAt(i).wakefulness;
+ if (wakefulness == WAKEFULNESS_AWAKE) {
+ return WAKEFULNESS_AWAKE;
+ } else if (wakefulness == WAKEFULNESS_DREAMING
+ && (deviceWakefulness == WAKEFULNESS_ASLEEP
+ || deviceWakefulness == WAKEFULNESS_DOZING)) {
+ deviceWakefulness = WAKEFULNESS_DREAMING;
+ } else if (wakefulness == WAKEFULNESS_DOZING
+ && deviceWakefulness == WAKEFULNESS_ASLEEP) {
+ deviceWakefulness = WAKEFULNESS_DOZING;
+ }
+ }
+
+ return deviceWakefulness;
+ }
+
+ /**
+ * Sets the {@code wakefulness} value for the {@link DisplayGroup} specified by the provided
+ * {@code groupId}.
+ *
+ * @return {@code true} if the wakefulness value was changed; {@code false} otherwise.
+ */
+ boolean setWakefulnessLocked(int groupId, int wakefulness) {
+ final DisplayGroupInfo displayGroupInfo = mDisplayGroupInfos.get(groupId);
+ if (displayGroupInfo.wakefulness != wakefulness) {
+ displayGroupInfo.wakefulness = wakefulness;
+ return true;
+ }
+
+ return false;
+ }
+
+ boolean isSandmanSummoned(int groupId) {
+ return mDisplayGroupInfos.get(groupId).sandmanSummoned;
+ }
+
+ boolean isSandmanSupported(int groupId) {
+ return mDisplayGroupInfos.get(groupId).supportsSandman;
+ }
+
+ /**
+ * Sets whether or not the sandman is summoned for the given {@code groupId}.
+ *
+ * @param groupId Signifies the DisplayGroup for which to summon or unsummon the
+ * sandman.
+ * @param sandmanSummoned {@code true} to summon the sandman; {@code false} to unsummon.
+ */
+ void setSandmanSummoned(int groupId, boolean sandmanSummoned) {
+ final DisplayGroupInfo displayGroupInfo = mDisplayGroupInfos.get(groupId);
+ displayGroupInfo.sandmanSummoned = displayGroupInfo.supportsSandman && sandmanSummoned;
+ }
+
+ /**
+ * Returns {@code true} if every display in the specified group has its requested state matching
+ * its actual state.
+ *
+ * @param groupId The identifier for the display group to check for readiness.
+ */
+ boolean isReady(int groupId) {
+ return mDisplayGroupInfos.get(groupId).ready;
+ }
+
+ /** Returns {@code true} if every display has its requested state matching its actual state. */
+ boolean areAllDisplaysReadyLocked() {
+ final int size = mDisplayGroupInfos.size();
+ for (int i = 0; i < size; i++) {
+ if (!mDisplayGroupInfos.valueAt(i).ready) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Sets whether the displays specified by the provided {@code groupId} are all ready.
+ *
+ * <p>A display is ready if its reported
+ * {@link DisplayManagerInternal.DisplayPowerCallbacks#onStateChanged() actual state} matches
+ * its {@link DisplayManagerInternal#requestPowerState requested state}.
+ *
+ * @param groupId The identifier for the display group.
+ * @param ready {@code true} if every display in the group is ready; otherwise {@code false}.
+ * @return {@code true} if the ready state changed; otherwise {@code false}.
+ */
+ boolean setDisplayGroupReadyLocked(int groupId, boolean ready) {
+ final DisplayGroupInfo displayGroupInfo = mDisplayGroupInfos.get(groupId);
+ if (displayGroupInfo.ready != ready) {
+ displayGroupInfo.ready = ready;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Interface through which an interested party may be informed of {@link DisplayGroup} events.
+ */
+ interface DisplayGroupPowerChangeListener {
+ int DISPLAY_GROUP_ADDED = 0;
+ int DISPLAY_GROUP_REMOVED = 1;
+ int DISPLAY_GROUP_CHANGED = 2;
+
+ void onDisplayGroupEventLocked(int event, int groupId);
+ }
+
+ private static final class DisplayGroupInfo {
+ public final DisplayPowerRequest displayPowerRequest;
+ public int wakefulness;
+ public boolean ready;
+ public long lastPowerOnTime;
+ public boolean sandmanSummoned;
+
+ /** {@code true} if this DisplayGroup supports dreaming; otherwise {@code false}. */
+ public boolean supportsSandman;
+
+ DisplayGroupInfo(DisplayPowerRequest displayPowerRequest, int wakefulness, boolean ready,
+ boolean supportsSandman) {
+ this.displayPowerRequest = displayPowerRequest;
+ this.wakefulness = wakefulness;
+ this.ready = ready;
+ this.supportsSandman = supportsSandman;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/power/DisplayPowerRequestMapper.java b/services/core/java/com/android/server/power/DisplayPowerRequestMapper.java
deleted file mode 100644
index 2fc3e40acd4d..000000000000
--- a/services/core/java/com/android/server/power/DisplayPowerRequestMapper.java
+++ /dev/null
@@ -1,121 +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.server.power;
-
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManagerInternal;
-import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
-import android.os.Handler;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.view.Display;
-
-import com.android.internal.annotations.GuardedBy;
-
-/**
- * Responsible for creating {@link DisplayPowerRequest}s and associating them with
- * {@link com.android.server.display.DisplayGroup}s.
- *
- * Each {@link com.android.server.display.DisplayGroup} has a single {@link DisplayPowerRequest}
- * which is used to request power state changes to every display in the group.
- */
-class DisplayPowerRequestMapper {
-
- private final Object mLock = new Object();
-
- /** A mapping from LogicalDisplay Id to DisplayGroup Id. */
- @GuardedBy("mLock")
- private final SparseIntArray mDisplayGroupIds = new SparseIntArray();
-
- /** A mapping from DisplayGroup Id to DisplayPowerRequest. */
- @GuardedBy("mLock")
- private final SparseArray<DisplayPowerRequest> mDisplayPowerRequests = new SparseArray<>();
-
- private final DisplayManagerInternal mDisplayManagerInternal;
-
- private final DisplayManager.DisplayListener mDisplayListener =
- new DisplayManager.DisplayListener() {
-
- @Override
- public void onDisplayAdded(int displayId) {
- synchronized (mLock) {
- if (mDisplayGroupIds.indexOfKey(displayId) >= 0) {
- return;
- }
- final int displayGroupId = mDisplayManagerInternal.getDisplayGroupId(
- displayId);
- if (!mDisplayPowerRequests.contains(displayGroupId)) {
- // A new DisplayGroup was created; create a new DisplayPowerRequest.
- mDisplayPowerRequests.append(displayGroupId, new DisplayPowerRequest());
- }
- mDisplayGroupIds.append(displayId, displayGroupId);
- }
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- synchronized (mLock) {
- final int index = mDisplayGroupIds.indexOfKey(displayId);
- if (index < 0) {
- return;
- }
- final int displayGroupId = mDisplayGroupIds.valueAt(index);
- mDisplayGroupIds.removeAt(index);
-
- if (mDisplayGroupIds.indexOfValue(displayGroupId) < 0) {
- // The DisplayGroup no longer exists; delete the DisplayPowerRequest.
- mDisplayPowerRequests.delete(displayGroupId);
- }
- }
- }
-
- @Override
- public void onDisplayChanged(int displayId) {
- synchronized (mLock) {
- final int newDisplayGroupId = mDisplayManagerInternal.getDisplayGroupId(
- displayId);
- final int oldDisplayGroupId = mDisplayGroupIds.get(displayId);
-
- if (!mDisplayPowerRequests.contains(newDisplayGroupId)) {
- // A new DisplayGroup was created; create a new DisplayPowerRequest.
- mDisplayPowerRequests.append(newDisplayGroupId,
- new DisplayPowerRequest());
- }
- mDisplayGroupIds.put(displayId, newDisplayGroupId);
-
- if (mDisplayGroupIds.indexOfValue(oldDisplayGroupId) < 0) {
- // The DisplayGroup no longer exists; delete the DisplayPowerRequest.
- mDisplayPowerRequests.delete(oldDisplayGroupId);
- }
- }
- }
- };
-
- DisplayPowerRequestMapper(DisplayManager displayManager,
- DisplayManagerInternal displayManagerInternal, Handler handler) {
- mDisplayManagerInternal = displayManagerInternal;
- displayManager.registerDisplayListener(mDisplayListener, handler);
- mDisplayPowerRequests.append(Display.DEFAULT_DISPLAY_GROUP, new DisplayPowerRequest());
- mDisplayGroupIds.append(Display.DEFAULT_DISPLAY, Display.DEFAULT_DISPLAY_GROUP);
- }
-
- DisplayPowerRequest get(int displayId) {
- synchronized (mLock) {
- return mDisplayPowerRequests.get(mDisplayGroupIds.get(displayId));
- }
- }
-}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index c07974aff0b9..bc117094dd68 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -16,8 +16,13 @@
package com.android.server.power;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.policyToString;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT;
+import static android.os.PowerManager.GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF;
+import static android.os.PowerManager.GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED;
+import static android.os.PowerManager.WAKE_REASON_DISPLAY_GROUP_ADDED;
+import static android.os.PowerManager.WAKE_REASON_DISPLAY_GROUP_TURNED_ON;
import static android.os.PowerManagerInternal.MODE_DEVICE_IDLE;
import static android.os.PowerManagerInternal.MODE_DISPLAY_INACTIVE;
import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
@@ -42,7 +47,6 @@ import android.database.ContentObserver;
import android.hardware.SensorManager;
import android.hardware.SystemSensorManager;
import android.hardware.display.AmbientDisplayConfiguration;
-import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.hardware.power.Boost;
@@ -178,6 +182,8 @@ public final class PowerManagerService extends SystemService
private static final int DIRTY_ATTENTIVE = 1 << 14;
// Dirty bit: phone flipped to face down
private static final int DIRTY_FACE_DOWN = 1 << 15;
+ // Dirty bit: display group power state has changed
+ private static final int DIRTY_DISPLAY_GROUP_POWER_UPDATED = 1 << 16;
// Summarizes the state of all active wakelocks.
private static final int WAKE_LOCK_CPU = 1 << 0;
@@ -300,10 +306,6 @@ public final class PowerManagerService extends SystemService
private int mWakefulnessRaw;
private boolean mWakefulnessChanging;
- // True if the sandman has just been summoned for the first time since entering the
- // dreaming or dozing state. Indicates whether a new dream should begin.
- private boolean mSandmanSummoned;
-
// True if MSG_SANDMAN has been scheduled.
private boolean mSandmanScheduled;
@@ -354,11 +356,7 @@ public final class PowerManagerService extends SystemService
// Manages the desired power state of displays. The actual state may lag behind the
// requested because it is updated asynchronously by the display power controller.
- private DisplayPowerRequestMapper mDisplayPowerRequestMapper;
-
- // True if the display power state has been fully applied, which means the display
- // is actually on or actually off or whatever was requested.
- private boolean mDisplayReady;
+ private DisplayGroupPowerStateMapper mDisplayGroupPowerStateMapper;
// The suspend blocker used to keep the CPU alive when an application has acquired
// a wake lock.
@@ -632,6 +630,39 @@ public final class PowerManagerService extends SystemService
// but the DreamService has not yet been told to start (it's an async process).
private boolean mDozeStartInProgress;
+ private final class DisplayGroupPowerChangeListener implements
+ DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener {
+ @Override
+ public void onDisplayGroupEventLocked(int event, int groupId) {
+ final int oldWakefulness = getWakefulnessLocked();
+ final int newWakefulness = mDisplayGroupPowerStateMapper.getGlobalWakefulnessLocked();
+ if (oldWakefulness != newWakefulness) {
+ final int reason;
+ switch (newWakefulness) {
+ case WAKEFULNESS_AWAKE:
+ reason = event == DISPLAY_GROUP_ADDED ? WAKE_REASON_DISPLAY_GROUP_ADDED
+ : WAKE_REASON_DISPLAY_GROUP_TURNED_ON;
+ break;
+ case WAKEFULNESS_DOZING:
+ reason = event == DISPLAY_GROUP_REMOVED
+ ? GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED
+ : GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF;
+ break;
+ default:
+ reason = 0;
+ }
+
+ setGlobalWakefulnessLocked(
+ mDisplayGroupPowerStateMapper.getGlobalWakefulnessLocked(),
+ mClock.uptimeMillis(), reason, Process.SYSTEM_UID, Process.SYSTEM_UID,
+ mContext.getOpPackageName(), "groupId: " + groupId);
+ }
+
+ mDirty |= DIRTY_DISPLAY_GROUP_POWER_UPDATED;
+ updatePowerStateLocked();
+ }
+ }
+
private final class ForegroundProfileObserver extends SynchronousUserSwitchObserver {
@Override
public void onUserSwitching(@UserIdInt int newUserId) throws RemoteException {
@@ -877,6 +908,12 @@ public final class PowerManagerService extends SystemService
void invalidateIsInteractiveCaches() {
PowerManager.invalidateIsInteractiveCaches();
}
+
+ DisplayGroupPowerStateMapper createDisplayPowerRequestMapper(Object lock,
+ DisplayManagerInternal displayManagerInternal,
+ DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener listener) {
+ return new DisplayGroupPowerStateMapper(lock, displayManagerInternal, listener);
+ }
}
final Constants mConstants;
@@ -1068,7 +1105,8 @@ public final class PowerManagerService extends SystemService
updatePowerStateLocked();
if (sQuiescent) {
- goToSleepNoUpdateLocked(mClock.uptimeMillis(),
+ sleepDisplayGroupNoUpdateLocked(Display.DEFAULT_DISPLAY_GROUP,
+ mClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_QUIESCENT,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
}
@@ -1085,8 +1123,8 @@ public final class PowerManagerService extends SystemService
mPolicy = getLocalService(WindowManagerPolicy.class);
mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
mAttentionDetector.systemReady(mContext);
- mDisplayPowerRequestMapper = new DisplayPowerRequestMapper(mContext.getSystemService(
- DisplayManager.class), mDisplayManagerInternal, mHandler);
+ mDisplayGroupPowerStateMapper = mInjector.createDisplayPowerRequestMapper(mLock,
+ mDisplayManagerInternal, new DisplayGroupPowerChangeListener());
SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
@@ -1404,9 +1442,11 @@ public final class PowerManagerService extends SystemService
opPackageName = wakeLock.mPackageName;
opUid = wakeLock.mOwnerUid;
}
- wakeUpNoUpdateLocked(mClock.uptimeMillis(),
- PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag,
- opUid, opPackageName, opUid);
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ wakeDisplayGroupNoUpdateLocked(id, mClock.uptimeMillis(),
+ PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag,
+ opUid, opPackageName, opUid);
+ }
}
}
@@ -1695,26 +1735,29 @@ public final class PowerManagerService extends SystemService
}
}
- private void wakeUpInternal(long eventTime, @WakeReason int reason, String details, int uid,
- String opPackageName, int opUid) {
+ private void wakeDisplayGroup(int groupId, long eventTime, @WakeReason int reason,
+ String details, int uid, String opPackageName, int opUid) {
synchronized (mLock) {
- if (wakeUpNoUpdateLocked(eventTime, reason, details, uid, opPackageName, opUid)) {
+ if (wakeDisplayGroupNoUpdateLocked(groupId, eventTime, reason, details, uid,
+ opPackageName, opUid)) {
updatePowerStateLocked();
}
}
}
- private boolean wakeUpNoUpdateLocked(long eventTime, @WakeReason int reason, String details,
- int reasonUid, String opPackageName, int opUid) {
+ private boolean wakeDisplayGroupNoUpdateLocked(int groupId, long eventTime,
+ @WakeReason int reason, String details, int uid, String opPackageName, int opUid) {
if (DEBUG_SPEW) {
- Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid);
+ Slog.d(TAG, "wakeDisplayGroupNoUpdateLocked: eventTime=" + eventTime
+ + ", groupId=" + groupId + ", uid=" + uid);
}
if (eventTime < mLastSleepTime || mForceSuspendActive || !mSystemReady) {
return false;
}
- if (getWakefulnessLocked() == WAKEFULNESS_AWAKE) {
+ final int currentState = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
+ if (currentState == WAKEFULNESS_AWAKE) {
if (!mBootCompleted && sQuiescent) {
mDirty |= DIRTY_QUIESCENT;
return true;
@@ -1722,113 +1765,90 @@ public final class PowerManagerService extends SystemService
return false;
}
- Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
-
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "powerOnDisplay");
try {
- Slog.i(TAG, "Waking up from "
- + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
- + " (uid=" + reasonUid
+ Slog.i(TAG, "Powering on display group from"
+ + PowerManagerInternal.wakefulnessToString(currentState)
+ + " (groupId=" + groupId
+ + ", uid=" + uid
+ ", reason=" + PowerManager.wakeReasonToString(reason)
+ ", details=" + details
+ ")...");
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, groupId);
- mLastWakeTime = eventTime;
- mLastWakeReason = reason;
- setWakefulnessLocked(WAKEFULNESS_AWAKE, reason, eventTime);
-
- mNotifier.onWakeUp(reason, details, reasonUid, opPackageName, opUid);
- userActivityNoUpdateLocked(
- eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
-
- if (sQuiescent) {
- mDirty |= DIRTY_QUIESCENT;
- }
+ setWakefulnessLocked(groupId, WAKEFULNESS_AWAKE, eventTime, uid, reason, opUid,
+ opPackageName, details);
+ mDisplayGroupPowerStateMapper.setLastPowerOnTimeLocked(groupId, eventTime);
+ mDirty |= DIRTY_DISPLAY_GROUP_POWER_UPDATED;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
+
return true;
}
- private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
+ private void sleepDisplayGroup(int groupId, long eventTime, int reason, int flags,
+ int uid) {
synchronized (mLock) {
- if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
+ if (sleepDisplayGroupNoUpdateLocked(groupId, eventTime, reason, flags, uid)) {
updatePowerStateLocked();
}
}
}
- /**
- * Puts the system in doze.
- *
- * This method is called goToSleep for historical reasons but actually attempts to DOZE,
- * and only tucks itself in to SLEEP if requested with the flag
- * {@link PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE}.
- */
- @SuppressWarnings("deprecation")
- private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
+ private boolean sleepDisplayGroupNoUpdateLocked(int groupId, long eventTime, int reason,
+ int flags, int uid) {
if (DEBUG_SPEW) {
- Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime
- + ", reason=" + reason + ", flags=" + flags + ", uid=" + uid);
+ Slog.d(TAG, "sleepDisplayGroupNoUpdateLocked: eventTime=" + eventTime
+ + ", groupId=" + groupId + ", reason=" + reason + ", flags=" + flags
+ + ", uid=" + uid);
}
if (eventTime < mLastWakeTime
- || getWakefulnessLocked() == WAKEFULNESS_ASLEEP
- || getWakefulnessLocked() == WAKEFULNESS_DOZING
+ || !PowerManagerInternal.isInteractive(getWakefulnessLocked())
|| !mSystemReady
|| !mBootCompleted) {
return false;
}
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep");
+ final int wakefulness = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
+ if (!PowerManagerInternal.isInteractive(wakefulness)) {
+ return false;
+ }
+
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "powerOffDisplay");
try {
reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX,
Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN));
- Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)
- + " (uid " + uid + ")...");
-
- mLastSleepTime = eventTime;
- mLastSleepReason = reason;
- mSandmanSummoned = true;
- mDozeStartInProgress = true;
- setWakefulnessLocked(WAKEFULNESS_DOZING, reason, eventTime);
-
- // Report the number of wake locks that will be cleared by going to sleep.
- int numWakeLocksCleared = 0;
- final int numWakeLocks = mWakeLocks.size();
- for (int i = 0; i < numWakeLocks; i++) {
- final WakeLock wakeLock = mWakeLocks.get(i);
- switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
- case PowerManager.FULL_WAKE_LOCK:
- case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
- case PowerManager.SCREEN_DIM_WAKE_LOCK:
- numWakeLocksCleared += 1;
- break;
- }
- }
- EventLogTags.writePowerSleepRequested(numWakeLocksCleared);
+ Slog.i(TAG, "Powering off display group due to "
+ + PowerManager.sleepReasonToString(reason) + " (groupId= " + groupId
+ + ", uid= " + uid + ")...");
- // Skip dozing if requested.
+ mDisplayGroupPowerStateMapper.setSandmanSummoned(groupId, true);
+ setWakefulnessLocked(groupId, WAKEFULNESS_DOZING, eventTime, uid, reason,
+ /* opUid= */ 0, /* opPackageName= */ null, /* details= */ null);
if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
- reallyGoToSleepNoUpdateLocked(eventTime, uid);
+ reallySleepDisplayGroupNoUpdateLocked(groupId, eventTime, uid);
}
+ mDirty |= DIRTY_DISPLAY_GROUP_POWER_UPDATED;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
- private void napInternal(long eventTime, int uid) {
+ private void dreamDisplayGroup(int groupId, long eventTime, int uid) {
synchronized (mLock) {
- if (napNoUpdateLocked(eventTime, uid)) {
+ if (dreamDisplayGroupNoUpdateLocked(groupId, eventTime, uid)) {
updatePowerStateLocked();
}
}
}
- private boolean napNoUpdateLocked(long eventTime, int uid) {
+ private boolean dreamDisplayGroupNoUpdateLocked(int groupId, long eventTime, int uid) {
if (DEBUG_SPEW) {
- Slog.d(TAG, "napNoUpdateLocked: eventTime=" + eventTime + ", uid=" + uid);
+ Slog.d(TAG, "dreamDisplayGroupNoUpdateLocked: eventTime=" + eventTime
+ + ", uid=" + uid);
}
if (eventTime < mLastWakeTime || getWakefulnessLocked() != WAKEFULNESS_AWAKE
@@ -1836,36 +1856,42 @@ public final class PowerManagerService extends SystemService
return false;
}
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "nap");
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "napDisplayGroup");
try {
- Slog.i(TAG, "Nap time (uid " + uid +")...");
+ Slog.i(TAG, "Napping display group (groupId=" + groupId + ", uid=" + uid + ")...");
+
+ mDisplayGroupPowerStateMapper.setSandmanSummoned(groupId, true);
+ setWakefulnessLocked(groupId, WAKEFULNESS_DREAMING, eventTime, uid, /* reason= */
+ 0, /* opUid= */ 0, /* opPackageName= */ null, /* details= */ null);
+ mDirty |= DIRTY_DISPLAY_GROUP_POWER_UPDATED;
- mSandmanSummoned = true;
- setWakefulnessLocked(WAKEFULNESS_DREAMING, 0, eventTime);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
- // Done dozing, drop everything and go to sleep.
- private boolean reallyGoToSleepNoUpdateLocked(long eventTime, int uid) {
+ private boolean reallySleepDisplayGroupNoUpdateLocked(int groupId, long eventTime, int uid) {
if (DEBUG_SPEW) {
- Slog.d(TAG, "reallyGoToSleepNoUpdateLocked: eventTime=" + eventTime
+ Slog.d(TAG, "reallySleepDisplayGroupNoUpdateLocked: eventTime=" + eventTime
+ ", uid=" + uid);
}
if (eventTime < mLastWakeTime || getWakefulnessLocked() == WAKEFULNESS_ASLEEP
- || !mBootCompleted || !mSystemReady) {
+ || !mBootCompleted || !mSystemReady
+ || mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId)
+ == WAKEFULNESS_ASLEEP) {
return false;
}
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "reallyGoToSleep");
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "reallySleepDisplayGroup");
try {
- Slog.i(TAG, "Sleeping (uid " + uid +")...");
+ Slog.i(TAG, "Sleeping display group (groupId=" + groupId + ", uid=" + uid + ")...");
- setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
- eventTime);
+ setWakefulnessLocked(groupId, WAKEFULNESS_ASLEEP, eventTime, uid,
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, /* opUid= */ 0,
+ /* opPackageName= */ null, /* details= */ null);
+ mDirty |= DIRTY_DISPLAY_GROUP_POWER_UPDATED;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
@@ -1873,8 +1899,62 @@ public final class PowerManagerService extends SystemService
}
@VisibleForTesting
- void setWakefulnessLocked(int wakefulness, int reason, long eventTime) {
- if (getWakefulnessLocked() != wakefulness) {
+ void setWakefulnessLocked(int groupId, int wakefulness, long eventTime, int uid, int reason,
+ int opUid, String opPackageName, String details) {
+ if (mDisplayGroupPowerStateMapper.setWakefulnessLocked(groupId, wakefulness)) {
+ setGlobalWakefulnessLocked(mDisplayGroupPowerStateMapper.getGlobalWakefulnessLocked(),
+ eventTime, reason, uid, opUid, opPackageName, details);
+ }
+ }
+
+ private void setGlobalWakefulnessLocked(int wakefulness, long eventTime, int reason, int uid,
+ int opUid, String opPackageName, String details) {
+ if (getWakefulnessLocked() == wakefulness) {
+ return;
+ }
+
+ // Phase 1: Handle pre-wakefulness change bookkeeping.
+ final String traceMethodName;
+ switch (wakefulness) {
+ case WAKEFULNESS_ASLEEP:
+ traceMethodName = "reallyGoToSleep";
+ Slog.i(TAG, "Sleeping (uid " + uid + ")...");
+ break;
+
+ case WAKEFULNESS_AWAKE:
+ traceMethodName = "wakeUp";
+ Slog.i(TAG, "Waking up from "
+ + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
+ + " (uid=" + uid
+ + ", reason=" + PowerManager.wakeReasonToString(reason)
+ + ", details=" + details
+ + ")...");
+ mLastWakeTime = eventTime;
+ mLastWakeReason = reason;
+ break;
+
+ case WAKEFULNESS_DREAMING:
+ traceMethodName = "nap";
+ Slog.i(TAG, "Nap time (uid " + uid + ")...");
+ break;
+
+ case WAKEFULNESS_DOZING:
+ traceMethodName = "goToSleep";
+ Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)
+ + " (uid " + uid + ")...");
+
+ mLastSleepTime = eventTime;
+ mLastSleepReason = reason;
+ mDozeStartInProgress = true;
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unexpected wakefulness: " + wakefulness);
+ }
+
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, traceMethodName);
+ try {
+ // Phase 2: Handle wakefulness change and bookkeeping.
// Under lock, invalidate before set ensures caches won't return stale values.
mInjector.invalidateIsInteractiveCaches();
mWakefulnessRaw = wakefulness;
@@ -1888,6 +1968,37 @@ public final class PowerManagerService extends SystemService
mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
}
mAttentionDetector.onWakefulnessChangeStarted(wakefulness);
+
+ // Phase 3: Handle post-wakefulness change bookkeeping.
+ switch (wakefulness) {
+ case WAKEFULNESS_AWAKE:
+ mNotifier.onWakeUp(reason, details, uid, opPackageName, opUid);
+ userActivityNoUpdateLocked(
+ eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
+ if (sQuiescent) {
+ mDirty |= DIRTY_QUIESCENT;
+ }
+ break;
+
+ case WAKEFULNESS_DOZING:
+ // Report the number of wake locks that will be cleared by going to sleep.
+ int numWakeLocksCleared = 0;
+ final int numWakeLocks = mWakeLocks.size();
+ for (int i = 0; i < numWakeLocks; i++) {
+ final WakeLock wakeLock = mWakeLocks.get(i);
+ switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
+ case PowerManager.FULL_WAKE_LOCK:
+ case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
+ case PowerManager.SCREEN_DIM_WAKE_LOCK:
+ numWakeLocksCleared += 1;
+ break;
+ }
+ }
+ EventLogTags.writePowerSleepRequested(numWakeLocksCleared);
+ break;
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
@@ -1910,7 +2021,7 @@ public final class PowerManagerService extends SystemService
}
private void finishWakefulnessChangeIfNeededLocked() {
- if (mWakefulnessChanging && mDisplayReady) {
+ if (mWakefulnessChanging && mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
if (getWakefulnessLocked() == WAKEFULNESS_DOZING
&& (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {
return; // wait until dream has enabled dozing
@@ -1922,13 +2033,6 @@ public final class PowerManagerService extends SystemService
|| getWakefulnessLocked() == WAKEFULNESS_ASLEEP) {
logSleepTimeoutRecapturedLocked();
}
- if (getWakefulnessLocked() == WAKEFULNESS_AWAKE) {
- Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
- final int latencyMs = (int) (mClock.uptimeMillis() - mLastWakeTime);
- if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) {
- Slog.w(TAG, "Screen on took " + latencyMs + " ms");
- }
- }
mWakefulnessChanging = false;
mNotifier.onWakefulnessChangeFinished();
}
@@ -2027,7 +2131,6 @@ public final class PowerManagerService extends SystemService
if ((dirty & DIRTY_BATTERY_STATE) != 0) {
final boolean wasPowered = mIsPowered;
final int oldPlugType = mPlugType;
- final boolean oldLevelLow = mBatteryLevelLow;
mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
mPlugType = mBatteryManagerInternal.getPlugType();
mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
@@ -2056,7 +2159,8 @@ public final class PowerManagerService extends SystemService
final long now = mClock.uptimeMillis();
if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,
dockedOnWirelessCharger)) {
- wakeUpNoUpdateLocked(now, PowerManager.WAKE_REASON_PLUGGED_IN,
+ wakeDisplayGroupNoUpdateLocked(Display.DEFAULT_DISPLAY_GROUP, now,
+ PowerManager.WAKE_REASON_PLUGGED_IN,
"android.server.power:PLUGGED:" + mIsPowered, Process.SYSTEM_UID,
mContext.getOpPackageName(), Process.SYSTEM_UID);
}
@@ -2340,7 +2444,8 @@ public final class PowerManagerService extends SystemService
nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
if (now < nextTimeout) {
final DisplayPowerRequest displayPowerRequest =
- mDisplayPowerRequestMapper.get(Display.DEFAULT_DISPLAY);
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(
+ Display.DEFAULT_DISPLAY_GROUP);
if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT
|| displayPowerRequest.policy == DisplayPowerRequest.POLICY_VR) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
@@ -2605,13 +2710,23 @@ public final class PowerManagerService extends SystemService
}
final long time = mClock.uptimeMillis();
if (isAttentiveTimeoutExpired(time)) {
- changed = goToSleepNoUpdateLocked(time, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
- PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
+ // TODO (b/175764389): Support per-display timeouts.
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ changed = sleepDisplayGroupNoUpdateLocked(id, time,
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
+ }
} else if (shouldNapAtBedTimeLocked()) {
- changed = napNoUpdateLocked(time, Process.SYSTEM_UID);
+ // TODO (b/175764389): Support per-display timeouts.
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ changed = dreamDisplayGroupNoUpdateLocked(id, time, Process.SYSTEM_UID);
+ }
} else {
- changed = goToSleepNoUpdateLocked(time,
- PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
+ // TODO (b/175764389): Support per-display timeouts.
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ changed = sleepDisplayGroupNoUpdateLocked(id, time,
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
+ }
}
}
}
@@ -2686,6 +2801,7 @@ public final class PowerManagerService extends SystemService
private void updateDreamLocked(int dirty, boolean displayBecameReady) {
if ((dirty & (DIRTY_WAKEFULNESS
| DIRTY_USER_ACTIVITY
+ | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED
| DIRTY_ATTENTIVE
| DIRTY_WAKE_LOCKS
| DIRTY_BOOT_COMPLETED
@@ -2694,7 +2810,7 @@ public final class PowerManagerService extends SystemService
| DIRTY_STAY_ON
| DIRTY_PROXIMITY_POSITIVE
| DIRTY_BATTERY_STATE)) != 0 || displayBecameReady) {
- if (mDisplayReady) {
+ if (mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
scheduleSandmanLocked();
}
}
@@ -2709,6 +2825,14 @@ public final class PowerManagerService extends SystemService
}
}
+ private void handleSandman() {
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ if (mDisplayGroupPowerStateMapper.isSandmanSupported(id)) {
+ handleSandman(id);
+ }
+ }
+ }
+
/**
* Called when the device enters or exits a dreaming or dozing state.
*
@@ -2716,16 +2840,19 @@ public final class PowerManagerService extends SystemService
* the dream and we don't want to hold our lock while doing so. There is a risk that
* the device will wake or go to sleep in the meantime so we have to handle that case.
*/
- private void handleSandman() { // runs on handler thread
+ private void handleSandman(int groupId) { // runs on handler thread
// Handle preconditions.
final boolean startDreaming;
final int wakefulness;
synchronized (mLock) {
mSandmanScheduled = false;
+ // TODO (b/175764708): Support per-display doze.
wakefulness = getWakefulnessLocked();
- if (mSandmanSummoned && mDisplayReady) {
- startDreaming = canDreamLocked() || canDozeLocked();
- mSandmanSummoned = false;
+ if ((wakefulness == WAKEFULNESS_DREAMING || wakefulness == WAKEFULNESS_DOZING) &&
+ mDisplayGroupPowerStateMapper.isSandmanSummoned(groupId)
+ && mDisplayGroupPowerStateMapper.isReady(groupId)) {
+ startDreaming = canDreamLocked(groupId) || canDozeLocked();
+ mDisplayGroupPowerStateMapper.setSandmanSummoned(groupId, false);
} else {
startDreaming = false;
}
@@ -2764,14 +2891,15 @@ public final class PowerManagerService extends SystemService
// If preconditions changed, wait for the next iteration to determine
// whether the dream should continue (or be restarted).
- if (mSandmanSummoned || getWakefulnessLocked() != wakefulness) {
+ if (mDisplayGroupPowerStateMapper.isSandmanSummoned(groupId)
+ || mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId) != wakefulness) {
return; // wait for next cycle
}
// Determine whether the dream should continue.
long now = mClock.uptimeMillis();
if (wakefulness == WAKEFULNESS_DREAMING) {
- if (isDreaming && canDreamLocked()) {
+ if (isDreaming && canDreamLocked(groupId)) {
if (mDreamsBatteryLevelDrainCutoffConfig >= 0
&& mBatteryLevel < mBatteryLevelWhenDreamStarted
- mDreamsBatteryLevelDrainCutoffConfig
@@ -2791,16 +2919,13 @@ public final class PowerManagerService extends SystemService
// Dream has ended or will be stopped. Update the power state.
if (isItBedTimeYetLocked()) {
- int flags = 0;
- if (isAttentiveTimeoutExpired(now)) {
- flags |= PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE;
- }
- goToSleepNoUpdateLocked(now, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, flags,
- Process.SYSTEM_UID);
+ final int flags = isAttentiveTimeoutExpired(now)
+ ? PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE : 0;
+ sleepDisplayGroupNoUpdateLocked(groupId, now,
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, flags, Process.SYSTEM_UID);
updatePowerStateLocked();
} else {
- wakeUpNoUpdateLocked(now,
- PowerManager.WAKE_REASON_UNKNOWN,
+ wakeDisplayGroupNoUpdateLocked(groupId, now, PowerManager.WAKE_REASON_UNKNOWN,
"android.server.power:DREAM_FINISHED", Process.SYSTEM_UID,
mContext.getOpPackageName(), Process.SYSTEM_UID);
updatePowerStateLocked();
@@ -2811,7 +2936,7 @@ public final class PowerManagerService extends SystemService
}
// Doze has ended or will be stopped. Update the power state.
- reallyGoToSleepNoUpdateLocked(now, Process.SYSTEM_UID);
+ reallySleepDisplayGroupNoUpdateLocked(groupId, now, Process.SYSTEM_UID);
updatePowerStateLocked();
}
}
@@ -2823,11 +2948,11 @@ public final class PowerManagerService extends SystemService
}
/**
- * Returns true if the device is allowed to dream in its current state.
+ * Returns true if the {@code groupId} is allowed to dream in its current state.
*/
- private boolean canDreamLocked() {
+ private boolean canDreamLocked(int groupId) {
final DisplayPowerRequest displayPowerRequest =
- mDisplayPowerRequestMapper.get(Display.DEFAULT_DISPLAY);
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(groupId);
if (getWakefulnessLocked() != WAKEFULNESS_DREAMING
|| !mDreamsSupportedConfig
|| !mDreamsEnabledSetting
@@ -2865,95 +2990,117 @@ public final class PowerManagerService extends SystemService
/**
* Updates the display power state asynchronously.
- * When the update is finished, mDisplayReady will be set to true. The display
- * controller posts a message to tell us when the actual display power state
+ * When the update is finished, the ready state of the displays will be updated. The display
+ * controllers post a message to tell us when the actual display power state
* has been updated so we come back here to double-check and finish up.
*
* This function recalculates the display power state each time.
*
- * @return true if the display became ready.
+ * @return {@code true} if all displays became ready; {@code false} otherwise
*/
private boolean updateDisplayPowerStateLocked(int dirty) {
- final boolean oldDisplayReady = mDisplayReady;
+ final boolean oldDisplayReady = mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked();
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
| DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_VR_MODE_CHANGED |
- DIRTY_QUIESCENT)) != 0) {
+ DIRTY_QUIESCENT | DIRTY_DISPLAY_GROUP_POWER_UPDATED)) != 0) {
if ((dirty & DIRTY_QUIESCENT) != 0) {
- if (mDisplayReady) {
+ if (mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
sQuiescent = false;
} else {
mDirty |= DIRTY_QUIESCENT;
}
}
- final DisplayPowerRequest displayPowerRequest = mDisplayPowerRequestMapper.get(
- Display.DEFAULT_DISPLAY);
- displayPowerRequest.policy = getDesiredScreenPolicyLocked();
-
- // Determine appropriate screen brightness and auto-brightness adjustments.
- final boolean autoBrightness;
- final float screenBrightnessOverride;
- if (!mBootCompleted) {
- // Keep the brightness steady during boot. This requires the
- // bootloader brightness and the default brightness to be identical.
- autoBrightness = false;
- screenBrightnessOverride = mScreenBrightnessDefault;
- } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
- autoBrightness = false;
- screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager;
- } else {
- autoBrightness = (mScreenBrightnessModeSetting ==
- Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
- screenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
- }
+ for (final int groupId : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ final DisplayPowerRequest displayPowerRequest =
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(groupId);
+ displayPowerRequest.policy = getDesiredScreenPolicyLocked(groupId);
+
+ // Determine appropriate screen brightness and auto-brightness adjustments.
+ final boolean autoBrightness;
+ final float screenBrightnessOverride;
+ if (!mBootCompleted) {
+ // Keep the brightness steady during boot. This requires the
+ // bootloader brightness and the default brightness to be identical.
+ autoBrightness = false;
+ screenBrightnessOverride = mScreenBrightnessDefault;
+ } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
+ autoBrightness = false;
+ screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager;
+ } else {
+ autoBrightness = (mScreenBrightnessModeSetting
+ == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+ screenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ }
- // Update display power request.
- displayPowerRequest.screenBrightnessOverride = screenBrightnessOverride;
- displayPowerRequest.useAutoBrightness = autoBrightness;
- displayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
- displayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();
+ // Update display power request.
+ displayPowerRequest.screenBrightnessOverride = screenBrightnessOverride;
+ displayPowerRequest.useAutoBrightness = autoBrightness;
+ displayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
+ displayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();
- updatePowerRequestFromBatterySaverPolicy(displayPowerRequest);
+ updatePowerRequestFromBatterySaverPolicy(displayPowerRequest);
- if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
- displayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
- if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0
- && !mDrawWakeLockOverrideFromSidekick) {
- if (displayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) {
- displayPowerRequest.dozeScreenState = Display.STATE_DOZE;
- }
- if (displayPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND) {
- displayPowerRequest.dozeScreenState = Display.STATE_ON;
+ if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
+ displayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
+ if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0
+ && !mDrawWakeLockOverrideFromSidekick) {
+ if (displayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) {
+ displayPowerRequest.dozeScreenState = Display.STATE_DOZE;
+ }
+ if (displayPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND) {
+ displayPowerRequest.dozeScreenState = Display.STATE_ON;
+ }
}
+ displayPowerRequest.dozeScreenBrightness =
+ mDozeScreenBrightnessOverrideFromDreamManagerFloat;
+ } else {
+ displayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN;
+ displayPowerRequest.dozeScreenBrightness =
+ PowerManager.BRIGHTNESS_INVALID_FLOAT;
}
- displayPowerRequest.dozeScreenBrightness =
- mDozeScreenBrightnessOverrideFromDreamManagerFloat;
- } else {
- displayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN;
- displayPowerRequest.dozeScreenBrightness =
- PowerManager.BRIGHTNESS_INVALID_FLOAT;
- }
- mDisplayReady = mDisplayManagerInternal.requestPowerState(Display.DEFAULT_DISPLAY_GROUP,
- displayPowerRequest, mRequestWaitForNegativeProximity);
- mRequestWaitForNegativeProximity = false;
+ final boolean ready = mDisplayManagerInternal.requestPowerState(groupId,
+ displayPowerRequest, mRequestWaitForNegativeProximity);
- if (DEBUG_SPEW) {
- Slog.d(TAG, "updateDisplayPowerStateLocked: mDisplayReady=" + mDisplayReady
- + ", policy=" + displayPowerRequest.policy
- + ", mWakefulness=" + getWakefulnessLocked()
- + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
- + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
- + ", mBootCompleted=" + mBootCompleted
- + ", screenBrightnessOverride=" + screenBrightnessOverride
- + ", useAutoBrightness=" + autoBrightness
- + ", mScreenBrightnessBoostInProgress=" + mScreenBrightnessBoostInProgress
- + ", mIsVrModeEnabled= " + mIsVrModeEnabled
- + ", sQuiescent=" + sQuiescent);
+ if (DEBUG_SPEW) {
+ Slog.d(TAG, "updateDisplayPowerStateLocked: displayReady=" + ready
+ + ", groupId=" + groupId
+ + ", policy=" + policyToString(displayPowerRequest.policy)
+ + ", mWakefulness="
+ + PowerManagerInternal.wakefulnessToString(
+ mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId))
+ + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
+ + ", mUserActivitySummary=0x" + Integer.toHexString(
+ mUserActivitySummary)
+ + ", mBootCompleted=" + mBootCompleted
+ + ", screenBrightnessOverride="
+ + displayPowerRequest.screenBrightnessOverride
+ + ", useAutoBrightness=" + displayPowerRequest.useAutoBrightness
+ + ", mScreenBrightnessBoostInProgress="
+ + mScreenBrightnessBoostInProgress
+ + ", mIsVrModeEnabled= " + mIsVrModeEnabled
+ + ", sQuiescent=" + sQuiescent);
+ }
+
+ final boolean displayReadyStateChanged =
+ mDisplayGroupPowerStateMapper.setDisplayGroupReadyLocked(groupId, ready);
+ if (ready && displayReadyStateChanged
+ && mDisplayGroupPowerStateMapper.getWakefulnessLocked(
+ groupId) == WAKEFULNESS_AWAKE) {
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, groupId);
+ final int latencyMs = (int) (mClock.uptimeMillis()
+ - mDisplayGroupPowerStateMapper.getLastPowerOnTimeLocked(groupId));
+ if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) {
+ Slog.w(TAG, "Screen on took " + latencyMs + " ms");
+ }
+ }
}
+ mRequestWaitForNegativeProximity = false;
}
- return mDisplayReady && !oldDisplayReady;
+
+ return mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked() && !oldDisplayReady;
}
private void updateScreenBrightnessBoostLocked(int dirty) {
@@ -2987,12 +3134,11 @@ public final class PowerManagerService extends SystemService
}
@VisibleForTesting
- int getDesiredScreenPolicyLocked() {
- if (getWakefulnessLocked() == WAKEFULNESS_ASLEEP || sQuiescent) {
+ int getDesiredScreenPolicyLocked(int groupId) {
+ final int wakefulness = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
+ if (wakefulness == WAKEFULNESS_ASLEEP || sQuiescent) {
return DisplayPowerRequest.POLICY_OFF;
- }
-
- if (getWakefulnessLocked() == WAKEFULNESS_DOZING) {
+ } else if (wakefulness == WAKEFULNESS_DOZING) {
if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
return DisplayPowerRequest.POLICY_DOZE;
}
@@ -3022,7 +3168,6 @@ public final class PowerManagerService extends SystemService
private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =
new DisplayManagerInternal.DisplayPowerCallbacks() {
- private int mDisplayState = Display.STATE_UNKNOWN;
@Override
public void onStateChanged() {
@@ -3053,29 +3198,25 @@ public final class PowerManagerService extends SystemService
}
@Override
- public void onDisplayStateChange(int state) {
+ public void onDisplayStateChange(boolean allInactive, boolean allOff) {
// This method is only needed to support legacy display blanking behavior
// where the display's power state is coupled to suspend or to the power HAL.
// The order of operations matters here.
synchronized (mLock) {
- if (mDisplayState != state) {
- mDisplayState = state;
- setPowerModeInternal(MODE_DISPLAY_INACTIVE,
- !Display.isActiveState(state));
- if (state == Display.STATE_OFF) {
- if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
- setHalInteractiveModeLocked(false);
- }
- if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
- setHalAutoSuspendModeLocked(true);
- }
- } else {
- if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
- setHalAutoSuspendModeLocked(false);
- }
- if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
- setHalInteractiveModeLocked(true);
- }
+ setPowerModeInternal(MODE_DISPLAY_INACTIVE, allInactive);
+ if (allOff) {
+ if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+ setHalInteractiveModeLocked(false);
+ }
+ if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+ setHalAutoSuspendModeLocked(true);
+ }
+ } else {
+ if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+ setHalAutoSuspendModeLocked(false);
+ }
+ if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+ setHalInteractiveModeLocked(true);
}
}
}
@@ -3090,13 +3231,6 @@ public final class PowerManagerService extends SystemService
public void releaseSuspendBlocker() {
mDisplaySuspendBlocker.release();
}
-
- @Override
- public String toString() {
- synchronized (this) {
- return "state=" + Display.stateToString(mDisplayState);
- }
- }
};
private boolean shouldUseProximitySensorLocked() {
@@ -3112,9 +3246,11 @@ public final class PowerManagerService extends SystemService
final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
final boolean autoSuspend = !needDisplaySuspendBlocker;
- final DisplayPowerRequest displayPowerRequest = mDisplayPowerRequestMapper.get(
- Display.DEFAULT_DISPLAY);
- final boolean interactive = displayPowerRequest.isBrightOrDim();
+ final int[] groupIds = mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked();
+ boolean interactive = false;
+ for (int id : groupIds) {
+ interactive |= mDisplayGroupPowerStateMapper.getPowerRequestLocked(id).isBrightOrDim();
+ }
// Disable auto-suspend if needed.
// FIXME We should consider just leaving auto-suspend enabled forever since
@@ -3144,7 +3280,7 @@ public final class PowerManagerService extends SystemService
// until the display is actually ready so that all transitions have
// completed. This is probably a good sign that things have gotten
// too tangled over here...
- if (interactive || mDisplayReady) {
+ if (interactive || mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
setHalInteractiveModeLocked(interactive);
}
}
@@ -3170,29 +3306,10 @@ public final class PowerManagerService extends SystemService
* We do so if the screen is on or is in transition between states.
*/
private boolean needDisplaySuspendBlockerLocked() {
- if (!mDisplayReady) {
+ if (!mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
return true;
}
- final DisplayPowerRequest displayPowerRequest = mDisplayPowerRequestMapper.get(
- Display.DEFAULT_DISPLAY);
- if (displayPowerRequest.isBrightOrDim()) {
- // If we asked for the screen to be on but it is off due to the proximity
- // sensor then we may suspend but only if the configuration allows it.
- // On some hardware it may not be safe to suspend because the proximity
- // sensor may not be correctly configured as a wake-up source.
- if (!displayPowerRequest.useProximitySensor || !mProximityPositive
- || !mSuspendWhenScreenOffDueToProximityConfig) {
- return true;
- }
- }
- if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE
- && displayPowerRequest.dozeScreenState == Display.STATE_ON) {
- // Although we are in DOZE and would normally allow the device to suspend,
- // the doze service has explicitly requested the display to remain in the ON
- // state which means we should hold the display suspend blocker.
- return true;
- }
if (mScreenBrightnessBoostInProgress) {
return true;
}
@@ -3206,6 +3323,30 @@ public final class PowerManagerService extends SystemService
return true;
}
+ final int[] groupIds = mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked();
+ for (int id : groupIds) {
+ final DisplayPowerRequest displayPowerRequest =
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(id);
+ if (displayPowerRequest.isBrightOrDim()) {
+ // If we asked for the screen to be on but it is off due to the proximity
+ // sensor then we may suspend but only if the configuration allows it.
+ // On some hardware it may not be safe to suspend because the proximity
+ // sensor may not be correctly configured as a wake-up source.
+ if (!displayPowerRequest.useProximitySensor || !mProximityPositive
+ || !mSuspendWhenScreenOffDueToProximityConfig) {
+ return true;
+ }
+ }
+
+ if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE
+ && displayPowerRequest.dozeScreenState == Display.STATE_ON) {
+ // Although we are in DOZE and would normally allow the device to suspend,
+ // the doze service has explicitly requested the display to remain in the ON
+ // state which means we should hold the display suspend blocker.
+ return true;
+ }
+ }
+
// Let the system suspend if the screen is off or dozing.
return false;
}
@@ -3739,9 +3880,15 @@ public final class PowerManagerService extends SystemService
synchronized (mLock) {
mForceSuspendActive = true;
// Place the system in an non-interactive state
- goToSleepInternal(mClock.uptimeMillis(),
- PowerManager.GO_TO_SLEEP_REASON_FORCE_SUSPEND,
- PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, uid);
+ boolean updatePowerState = false;
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ updatePowerState |= sleepDisplayGroupNoUpdateLocked(id, mClock.uptimeMillis(),
+ PowerManager.GO_TO_SLEEP_REASON_FORCE_SUSPEND,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, uid);
+ }
+ if (updatePowerState) {
+ updatePowerStateLocked();
+ }
// Disable all the partial wake locks as well
updateWakeLockDisabledStatesLocked();
@@ -3881,7 +4028,6 @@ public final class PowerManagerService extends SystemService
pw.println(" mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary));
pw.println(" mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
pw.println(" mSandmanScheduled=" + mSandmanScheduled);
- pw.println(" mSandmanSummoned=" + mSandmanSummoned);
pw.println(" mBatteryLevelLow=" + mBatteryLevelLow);
pw.println(" mLightDeviceIdleMode=" + mLightDeviceIdleMode);
pw.println(" mDeviceIdleMode=" + mDeviceIdleMode);
@@ -3899,7 +4045,6 @@ public final class PowerManagerService extends SystemService
+ TimeUtils.formatUptime(mLastScreenBrightnessBoostTime));
pw.println(" mScreenBrightnessBoostInProgress="
+ mScreenBrightnessBoostInProgress);
- pw.println(" mDisplayReady=" + mDisplayReady);
pw.println(" mHoldingWakeLockSuspendBlocker=" + mHoldingWakeLockSuspendBlocker);
pw.println(" mHoldingDisplaySuspendBlocker=" + mHoldingDisplaySuspendBlocker);
pw.println(" mLastFlipTime=" + mLastFlipTime);
@@ -4138,7 +4283,6 @@ public final class PowerManagerService extends SystemService
PowerManagerServiceDumpProto.IS_REQUEST_WAIT_FOR_NEGATIVE_PROXIMITY,
mRequestWaitForNegativeProximity);
proto.write(PowerManagerServiceDumpProto.IS_SANDMAN_SCHEDULED, mSandmanScheduled);
- proto.write(PowerManagerServiceDumpProto.IS_SANDMAN_SUMMONED, mSandmanSummoned);
proto.write(PowerManagerServiceDumpProto.IS_BATTERY_LEVEL_LOW, mBatteryLevelLow);
proto.write(PowerManagerServiceDumpProto.IS_LIGHT_DEVICE_IDLE_MODE, mLightDeviceIdleMode);
proto.write(PowerManagerServiceDumpProto.IS_DEVICE_IDLE_MODE, mDeviceIdleMode);
@@ -4165,7 +4309,6 @@ public final class PowerManagerService extends SystemService
proto.write(
PowerManagerServiceDumpProto.IS_SCREEN_BRIGHTNESS_BOOST_IN_PROGRESS,
mScreenBrightnessBoostInProgress);
- proto.write(PowerManagerServiceDumpProto.IS_DISPLAY_READY, mDisplayReady);
proto.write(
PowerManagerServiceDumpProto.IS_HOLDING_WAKE_LOCK_SUSPEND_BLOCKER,
mHoldingWakeLockSuspendBlocker);
@@ -4979,7 +5122,8 @@ public final class PowerManagerService extends SystemService
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- wakeUpInternal(eventTime, reason, details, uid, opPackageName, uid);
+ wakeDisplayGroup(Display.DEFAULT_DISPLAY_GROUP, eventTime, reason, details, uid,
+ opPackageName, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -4997,7 +5141,7 @@ public final class PowerManagerService extends SystemService
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- goToSleepInternal(eventTime, reason, flags, uid);
+ sleepDisplayGroup(Display.DEFAULT_DISPLAY_GROUP, eventTime, reason, flags, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -5015,7 +5159,7 @@ public final class PowerManagerService extends SystemService
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- napInternal(eventTime, uid);
+ dreamDisplayGroup(Display.DEFAULT_DISPLAY_GROUP, eventTime, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -5677,7 +5821,8 @@ public final class PowerManagerService extends SystemService
// also tells us that we're not already ignoring the proximity sensor.
final DisplayPowerRequest displayPowerRequest =
- mDisplayPowerRequestMapper.get(Display.DEFAULT_DISPLAY);
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(
+ Display.DEFAULT_DISPLAY_GROUP);
if (displayPowerRequest.useProximitySensor && mProximityPositive) {
mDisplayManagerInternal.ignoreProximitySensorUntilChanged();
return true;
diff --git a/services/core/java/com/android/server/speech/Android.bp b/services/core/java/com/android/server/speech/Android.bp
index 379b0754b82a..5605349812da 100644
--- a/services/core/java/com/android/server/speech/Android.bp
+++ b/services/core/java/com/android/server/speech/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
filegroup {
name: "services.speech-sources",
srcs: ["java/**/*.java"],
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index a390df9edae1..8ffbb0a87dc0 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -1336,7 +1336,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
}
@Override
- public void onNotificationClear(String pkg, String tag, int id, int userId, String key,
+ public void onNotificationClear(String pkg, int userId, String key,
@NotificationStats.DismissalSurface int dismissalSurface,
@NotificationStats.DismissalSentiment int dismissalSentiment,
NotificationVisibility nv) {
@@ -1345,7 +1345,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
final int callingPid = Binder.getCallingPid();
final long identity = Binder.clearCallingIdentity();
try {
- mNotificationDelegate.onNotificationClear(callingUid, callingPid, pkg, tag, id, userId,
+ mNotificationDelegate.onNotificationClear(callingUid, callingPid, pkg, userId,
key, dismissalSurface, dismissalSentiment, nv);
} finally {
Binder.restoreCallingIdentity(identity);
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 9ee072ee7ce5..06748a3aa2d1 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -969,7 +969,7 @@ public class VcnGatewayConnection extends StateMachine {
mGatewayStatusCallback.onGatewayConnectionError(
mConnectionConfig.getRequiredUnderlyingCapabilities(),
VCN_ERROR_CODE_INTERNAL_ERROR,
- "java.lang.RuntimeException",
+ RuntimeException.class.getName(),
"Received "
+ exception.getClass().getSimpleName()
+ " with message: "
@@ -991,11 +991,11 @@ public class VcnGatewayConnection extends StateMachine {
} else if (exception instanceof IkeInternalException
&& exception.getCause() instanceof IOException) {
errorCode = VCN_ERROR_CODE_NETWORK_ERROR;
- exceptionClass = "java.io.IOException";
+ exceptionClass = IOException.class.getName();
exceptionMessage = exception.getCause().getMessage();
} else {
errorCode = VCN_ERROR_CODE_INTERNAL_ERROR;
- exceptionClass = "java.lang.RuntimeException";
+ exceptionClass = RuntimeException.class.getName();
exceptionMessage =
"Received "
+ exception.getClass().getSimpleName()
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5d3b9c197267..dd9619ae815a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3624,7 +3624,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
// Reset the last saved PiP snap fraction on removal.
- mDisplayContent.mPinnedStackControllerLocked.onActivityHidden(mActivityComponent);
+ mDisplayContent.mPinnedTaskControllerLocked.onActivityHidden(mActivityComponent);
mWmService.mEmbeddedWindowController.onActivityRemoved(this);
mRemovingFromDisplay = false;
}
@@ -4976,7 +4976,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this);
mAppStopped = true;
// Reset the last saved PiP snap fraction on app stop.
- mDisplayContent.mPinnedStackControllerLocked.onActivityHidden(mActivityComponent);
+ mDisplayContent.mPinnedTaskControllerLocked.onActivityHidden(mActivityComponent);
destroySurfaces();
// Remove any starting window that was added for this app if they are still around.
removeStartingWindow();
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index f505daa9b628..a7312b321e4d 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -67,39 +67,40 @@ import java.util.function.BiFunction;
* .setImeContainer(imeContainer)
* .setTaskDisplayAreas(rootTdaList);
*
- * // Build root hierarchy of front and rear DisplayAreaGroup.
- * RootDisplayArea frontRoot = new RootDisplayArea(wmService, "FrontRoot", FEATURE_FRONT_ROOT);
- * DisplayAreaPolicyBuilder.HierarchyBuilder frontGroupHierarchy =
- * new DisplayAreaPolicyBuilder.HierarchyBuilder(frontRoot)
+ * // Build root hierarchy of first and second DisplayAreaGroup.
+ * RootDisplayArea firstRoot = new RootDisplayArea(wmService, "FirstRoot", FEATURE_FIRST_ROOT);
+ * DisplayAreaPolicyBuilder.HierarchyBuilder firstGroupHierarchy =
+ * new DisplayAreaPolicyBuilder.HierarchyBuilder(firstRoot)
* // (Optional) .addFeature(...)
- * .setTaskDisplayAreas(frontTdaList);
+ * .setTaskDisplayAreas(firstTdaList);
*
- * RootDisplayArea rearRoot = new RootDisplayArea(wmService, "RearRoot", FEATURE_REAR_ROOT);
- * DisplayAreaPolicyBuilder.HierarchyBuilder rearGroupHierarchy =
- * new DisplayAreaPolicyBuilder.HierarchyBuilder(rearRoot)
+ * RootDisplayArea secondRoot = new RootDisplayArea(wmService, "SecondRoot",
+ * FEATURE_REAR_ROOT);
+ * DisplayAreaPolicyBuilder.HierarchyBuilder secondGroupHierarchy =
+ * new DisplayAreaPolicyBuilder.HierarchyBuilder(secondRoot)
* // (Optional) .addFeature(...)
- * .setTaskDisplayAreas(rearTdaList);
+ * .setTaskDisplayAreas(secondTdaList);
*
* // Define the function to select root for window to attach.
* BiFunction<WindowToken, Bundle, RootDisplayArea> selectRootForWindowFunc =
- * (windowToken, bundle) -> {
- * if (bundle == null) {
+ * (windowToken, options) -> {
+ * if (options == null) {
* return root;
* }
* // OEMs need to define the condition.
* if (...) {
- * return frontRoot;
+ * return firstRoot;
* }
* if (...) {
- * return rearRoot;
+ * return secondRoot;
* }
* return root;
* };
*
* return new DisplayAreaPolicyBuilder()
* .setRootHierarchy(rootHierarchy)
- * .addDisplayAreaGroupHierarchy(frontGroupHierarchy)
- * .addDisplayAreaGroupHierarchy(rearGroupHierarchy)
+ * .addDisplayAreaGroupHierarchy(firstGroupHierarchy)
+ * .addDisplayAreaGroupHierarchy(secondGroupHierarchy)
* .setSelectRootForWindowFunc(selectRootForWindowFunc)
* .build(wmService, content);
* </pre>
@@ -110,12 +111,12 @@ import java.util.function.BiFunction;
* - WindowedMagnification
* - DisplayArea.Tokens (Wallpapers can be attached here)
* - TaskDisplayArea
- * - RootDisplayArea (FrontRoot)
+ * - RootDisplayArea (FirstRoot)
* - DisplayArea.Tokens (Wallpapers can be attached here)
* - TaskDisplayArea
* - DisplayArea.Tokens (windows above Tasks up to IME can be attached here)
* - DisplayArea.Tokens (windows above IME can be attached here)
- * - RootDisplayArea (RearRoot)
+ * - RootDisplayArea (SecondRoot)
* - DisplayArea.Tokens (Wallpapers can be attached here)
* - TaskDisplayArea
* - DisplayArea.Tokens (windows above Tasks up to IME can be attached here)
@@ -133,14 +134,23 @@ import java.util.function.BiFunction;
* {@link RootDisplayArea}.
*/
class DisplayAreaPolicyBuilder {
+
+ /**
+ * Key to specify the {@link RootDisplayArea} to attach the window to. Should be used by the
+ * function passed in from {@link #setSelectRootForWindowFunc(BiFunction)}
+ */
+ static final String KEY_ROOT_DISPLAY_AREA_ID = "root_display_area_id";
+
@Nullable private HierarchyBuilder mRootHierarchyBuilder;
- private ArrayList<HierarchyBuilder> mDisplayAreaGroupHierarchyBuilders = new ArrayList<>();
+ private final ArrayList<HierarchyBuilder> mDisplayAreaGroupHierarchyBuilders =
+ new ArrayList<>();
/**
* When a window is created, the policy will use this function, which takes window type and
* options, to select the {@link RootDisplayArea} to place that window in. The selected root
* can be either the one of the {@link #mRootHierarchyBuilder} or the one of any of the
* {@link #mDisplayAreaGroupHierarchyBuilders}.
+ * @see DefaultSelectRootForWindowFunction as an example.
**/
@Nullable private BiFunction<Integer, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
@@ -160,7 +170,10 @@ class DisplayAreaPolicyBuilder {
return this;
}
- /** The policy will use this function to find the root to place windows in. */
+ /**
+ * The policy will use this function to find the root to place windows in.
+ * @see DefaultSelectRootForWindowFunction as an example.
+ */
DisplayAreaPolicyBuilder setSelectRootForWindowFunc(
BiFunction<Integer, Bundle, RootDisplayArea> selectRootForWindowFunc) {
mSelectRootForWindowFunc = selectRootForWindowFunc;
@@ -169,7 +182,7 @@ class DisplayAreaPolicyBuilder {
/**
* Makes sure the setting meets the requirement:
- * 1. {@link mRootHierarchyBuilder} must be set.
+ * 1. {@link #mRootHierarchyBuilder} must be set.
* 2. {@link RootDisplayArea} and {@link TaskDisplayArea} must have unique ids.
* 3. {@link Feature} below the same {@link RootDisplayArea} must have unique ids.
* 4. There must be exactly one {@link HierarchyBuilder} that contains the IME container.
@@ -309,11 +322,57 @@ class DisplayAreaPolicyBuilder {
hierarchyBuilder.build();
displayAreaGroupRoots.add(hierarchyBuilder.mRoot);
}
+ // Use the default function if it is not specified otherwise.
+ if (mSelectRootForWindowFunc == null) {
+ mSelectRootForWindowFunc = new DefaultSelectRootForWindowFunction(
+ mRootHierarchyBuilder.mRoot, displayAreaGroupRoots);
+ }
return new Result(wmService, mRootHierarchyBuilder.mRoot, displayAreaGroupRoots,
mSelectRootForWindowFunc);
}
/**
+ * The default function to be used for finding {@link RootDisplayArea} for window to be attached
+ * to if there is no other function set through {@link #setSelectRootForWindowFunc(BiFunction)}.
+ *
+ * When a window is created with {@link Bundle} options, this function will select the
+ * {@link RootDisplayArea} based on the options. Returns {@link #mDisplayRoot} if there is no
+ * match found.
+ */
+ private static class DefaultSelectRootForWindowFunction implements
+ BiFunction<Integer, Bundle, RootDisplayArea> {
+ final RootDisplayArea mDisplayRoot;
+ final List<RootDisplayArea> mDisplayAreaGroupRoots;
+
+ DefaultSelectRootForWindowFunction(RootDisplayArea displayRoot,
+ List<RootDisplayArea> displayAreaGroupRoots) {
+ mDisplayRoot = displayRoot;
+ mDisplayAreaGroupRoots = Collections.unmodifiableList(displayAreaGroupRoots);
+ }
+
+ @Override
+ public RootDisplayArea apply(Integer windowType, Bundle options) {
+ if (mDisplayAreaGroupRoots.isEmpty()) {
+ return mDisplayRoot;
+ }
+
+ // Select the RootDisplayArea set in options.
+ if (options != null && options.containsKey(KEY_ROOT_DISPLAY_AREA_ID)) {
+ final int rootId = options.getInt(KEY_ROOT_DISPLAY_AREA_ID);
+ if (mDisplayRoot.mFeatureId == rootId) {
+ return mDisplayRoot;
+ }
+ for (int i = mDisplayAreaGroupRoots.size() - 1; i >= 0; i--) {
+ if (mDisplayAreaGroupRoots.get(i).mFeatureId == rootId) {
+ return mDisplayAreaGroupRoots.get(i);
+ }
+ }
+ }
+ return mDisplayRoot;
+ }
+ }
+
+ /**
* Builder to define {@link Feature} and {@link DisplayArea} hierarchy under a
* {@link RootDisplayArea}
*/
@@ -672,15 +731,10 @@ class DisplayAreaPolicyBuilder {
Result(WindowManagerService wmService, RootDisplayArea root,
List<RootDisplayArea> displayAreaGroupRoots,
- @Nullable BiFunction<Integer, Bundle, RootDisplayArea>
- selectRootForWindowFunc) {
+ BiFunction<Integer, Bundle, RootDisplayArea> selectRootForWindowFunc) {
super(wmService, root);
mDisplayAreaGroupRoots = Collections.unmodifiableList(displayAreaGroupRoots);
- mSelectRootForWindowFunc = selectRootForWindowFunc == null
- // Always return the highest level root of the logical display when the func is
- // not specified.
- ? (type, options) -> mRoot
- : selectRootForWindowFunc;
+ mSelectRootForWindowFunc = selectRootForWindowFunc;
// Cache the default TaskDisplayArea for quick access.
mDefaultTaskDisplayArea = mRoot.getItemFromTaskDisplayAreas(taskDisplayArea ->
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0143e70f53ca..eff4ea6536bd 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -36,6 +36,7 @@ import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static android.os.Build.VERSION_CODES.N;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.util.RotationUtils.deltaRotation;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
import static android.view.Display.FLAG_PRIVATE;
@@ -47,7 +48,6 @@ import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.view.View.GONE;
@@ -150,7 +150,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.WindowConfiguration;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.ScreenOrientation;
@@ -158,10 +157,8 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Insets;
-import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Region.Op;
import android.hardware.HardwareBuffer;
@@ -206,6 +203,7 @@ import android.view.MagnificationSpec;
import android.view.RemoteAnimationDefinition;
import android.view.RoundedCorners;
import android.view.Surface;
+import android.view.Surface.Rotation;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
@@ -449,8 +447,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
/** Save allocating when calculating rects */
private final Rect mTmpRect = new Rect();
private final Rect mTmpRect2 = new Rect();
- private final RectF mTmpRectF = new RectF();
- private final Matrix mTmpMatrix = new Matrix();
private final Region mTmpRegion = new Region();
/** Used for handing back size of display */
@@ -461,8 +457,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
/** Remove this display when animation on it has completed. */
private boolean mDeferredRemoval;
- final DockedStackDividerController mDividerControllerLocked;
- final PinnedStackController mPinnedStackControllerLocked;
+ final DockedTaskDividerController mDividerControllerLocked;
+ final PinnedTaskController mPinnedTaskControllerLocked;
final ArrayList<WindowState> mTapExcludedWindows = new ArrayList<>();
/** A collection of windows that provide tap exclude regions inside of them. */
@@ -1012,8 +1008,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mDisplayPolicy.systemReady();
}
mWindowCornerRadius = mDisplayPolicy.getWindowCornerRadius();
- mDividerControllerLocked = new DockedStackDividerController(this);
- mPinnedStackControllerLocked = new PinnedStackController(mWmService, this);
+ mDividerControllerLocked = new DockedTaskDividerController(this);
+ mPinnedTaskControllerLocked = new PinnedTaskController(mWmService, this);
final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(mSession)
.setOpaque(true)
@@ -1289,7 +1285,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return mInsetsPolicy;
}
- @Surface.Rotation
+ @Rotation
int getRotation() {
return mDisplayRotation.getRotation();
}
@@ -1479,7 +1475,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* Returns a valid rotation if the activity can use different orientation than the display.
* Otherwise {@link #ROTATION_UNDEFINED}.
*/
- @Surface.Rotation
+ @Rotation
int rotationForActivityInDifferentOrientation(@NonNull ActivityRecord r) {
if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM) {
return ROTATION_UNDEFINED;
@@ -1567,7 +1563,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// has it own policy for bounds, the activity bounds based on parent is unknown.
return false;
}
- if (mPinnedStackControllerLocked.isPipActiveOrWindowingModeChanging()) {
+ if (mPinnedTaskControllerLocked.isPipActiveOrWindowingModeChanging()) {
// Use normal rotation animation because seamless PiP rotation is not supported yet.
return false;
}
@@ -1614,7 +1610,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* Sets the provided record to {@link #mFixedRotationLaunchingApp} if possible to apply fixed
* rotation transform to it and indicate that the display may be rotated after it is launched.
*/
- void setFixedRotationLaunchingApp(@NonNull ActivityRecord r, @Surface.Rotation int rotation) {
+ void setFixedRotationLaunchingApp(@NonNull ActivityRecord r, @Rotation int rotation) {
final WindowToken prevRotatedLaunchingApp = mFixedRotationLaunchingApp;
if (prevRotatedLaunchingApp == r
&& r.getWindowConfiguration().getRotation() == rotation) {
@@ -2296,12 +2292,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
- DockedStackDividerController getDockedDividerController() {
+ DockedTaskDividerController getDockedDividerController() {
return mDividerControllerLocked;
}
- PinnedStackController getPinnedStackController() {
- return mPinnedStackControllerLocked;
+ PinnedTaskController getPinnedTaskController() {
+ return mPinnedTaskControllerLocked;
}
/**
@@ -2382,10 +2378,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* for bounds calculations.
*/
void preOnConfigurationChanged() {
- final PinnedStackController pinnedStackController = getPinnedStackController();
+ final PinnedTaskController pinnedTaskController = getPinnedTaskController();
- if (pinnedStackController != null) {
- getPinnedStackController().onConfigurationChanged();
+ if (pinnedTaskController != null) {
+ getPinnedTaskController().onConfigurationChanged();
}
}
@@ -2929,7 +2925,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final boolean imeVisible = imeWin != null && imeWin.isVisible()
&& imeWin.isDisplayed();
final int imeHeight = getInputMethodWindowVisibleHeight();
- mPinnedStackControllerLocked.setAdjustedForIme(imeVisible, imeHeight);
+ mPinnedTaskControllerLocked.setAdjustedForIme(imeVisible, imeHeight);
}
int getInputMethodWindowVisibleHeight() {
@@ -2951,27 +2947,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
forAllRootTasks(Task::prepareFreezingTaskBounds);
}
- void rotateBounds(int oldRotation, int newRotation, Rect bounds) {
- getBounds(mTmpRect, newRotation);
- rotateBounds(mTmpRect, oldRotation, newRotation, bounds);
- }
-
- void rotateBounds(Rect parentBounds, int oldRotation, int newRotation, Rect bounds) {
- // Compute a transform matrix to undo the coordinate space transformation,
- // and present the window at the same physical position it previously occupied.
- final int deltaRotation = deltaRotation(newRotation, oldRotation);
- createRotationMatrix(
- deltaRotation, parentBounds.width(), parentBounds.height(), mTmpMatrix);
-
- mTmpRectF.set(bounds);
- mTmpMatrix.mapRect(mTmpRectF);
- mTmpRectF.round(bounds);
- }
-
- static int deltaRotation(int oldRotation, int newRotation) {
- int delta = newRotation - oldRotation;
- if (delta < 0) delta += 4;
- return delta;
+ void rotateBounds(@Rotation int oldRotation, @Rotation int newRotation, Rect inOutBounds) {
+ // Get display bounds on oldRotation as parent bounds for the rotation.
+ getBounds(mTmpRect, oldRotation);
+ RotationUtils.rotateBounds(inOutBounds, mTmpRect, oldRotation, newRotation);
}
public void setRotationAnimation(ScreenRotationAnimation screenRotationAnimation) {
@@ -2985,35 +2964,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return mScreenRotationAnimation;
}
- private static void createRotationMatrix(int rotation, float displayWidth, float displayHeight,
- Matrix outMatrix) {
- // For rotations without Z-ordering we don't need the target rectangle's position.
- createRotationMatrix(rotation, 0 /* rectLeft */, 0 /* rectTop */, displayWidth,
- displayHeight, outMatrix);
- }
-
- static void createRotationMatrix(int rotation, float rectLeft, float rectTop,
- float displayWidth, float displayHeight, Matrix outMatrix) {
- switch (rotation) {
- case ROTATION_0:
- outMatrix.reset();
- break;
- case ROTATION_270:
- outMatrix.setRotate(270, 0, 0);
- outMatrix.postTranslate(0, displayHeight);
- outMatrix.postTranslate(rectTop, 0);
- break;
- case ROTATION_180:
- outMatrix.reset();
- break;
- case ROTATION_90:
- outMatrix.setRotate(90, 0, 0);
- outMatrix.postTranslate(displayWidth, 0);
- outMatrix.postTranslate(-rectTop, rectLeft);
- break;
- }
- }
-
@Override
public void dumpDebug(ProtoOutputStream proto, long fieldId,
@WindowTraceLogLevel int logLevel) {
@@ -3200,7 +3150,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
pw.println();
- mPinnedStackControllerLocked.dump(prefix, pw);
+ mPinnedTaskControllerLocked.dump(prefix, pw);
pw.println();
mDisplayFrames.dump(prefix, pw);
@@ -3639,8 +3589,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
private boolean isImeControlledByApp() {
- return mImeInputTarget != null && !WindowConfiguration.isSplitScreenWindowingMode(
- mImeInputTarget.getWindowingMode());
+ return mImeInputTarget != null && !mImeInputTarget.inMultiWindowMode();
}
boolean isImeAttachedToApp() {
@@ -4289,17 +4238,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
out.set(left, top, left + width, top + height);
}
- private void getBounds(Rect out, int orientation) {
+ private void getBounds(Rect out, @Rotation int rotation) {
getBounds(out);
// Rotate the Rect if needed.
final int currentRotation = mDisplayInfo.rotation;
- final int rotationDelta = deltaRotation(currentRotation, orientation);
+ final int rotationDelta = deltaRotation(currentRotation, rotation);
if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) {
- createRotationMatrix(rotationDelta, mBaseDisplayWidth, mBaseDisplayHeight, mTmpMatrix);
- mTmpRectF.set(out);
- mTmpMatrix.mapRect(mTmpRectF);
- mTmpRectF.round(out);
+ out.set(0, 0, out.height(), out.width());
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 5460e36a5f1b..f64f04cc0829 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -24,6 +24,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
+import static android.util.RotationUtils.deltaRotation;
+import static android.util.RotationUtils.rotateBounds;
import static android.view.Display.TYPE_INTERNAL;
import static android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES;
import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
@@ -1046,11 +1048,17 @@ public class DisplayPolicy {
return;
}
- // Get displayFrames bounds
- sTmpDisplayFrameBounds.set(0, 0, displayFrames.mDisplayWidth, displayFrames.mDisplayHeight);
+ // Get displayFrames bounds as it is on WindowState's rotation.
+ final int deltaRotation = deltaRotation(windowRotation, displayFrames.mRotation);
+ if (deltaRotation == Surface.ROTATION_90 || deltaRotation == Surface.ROTATION_270) {
+ sTmpDisplayFrameBounds.set(
+ 0, 0, displayFrames.mDisplayHeight, displayFrames.mDisplayWidth);
+ } else {
+ sTmpDisplayFrameBounds.set(
+ 0, 0, displayFrames.mDisplayWidth, displayFrames.mDisplayHeight);
+ }
// Rotate the WindowState's bounds based on the displayFrames rotation
- mDisplayContent.rotateBounds(sTmpDisplayFrameBounds, windowRotation,
- displayFrames.mRotation, outBounds);
+ rotateBounds(outBounds, sTmpDisplayFrameBounds, deltaRotation);
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index b106657dee99..63cb38a59349 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.util.RotationUtils.deltaRotation;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
@@ -475,7 +476,7 @@ public class DisplayRotation {
"Display id=%d rotation changed to %d from %d, lastOrientation=%d",
displayId, rotation, oldRotation, lastOrientation);
- if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
+ if (deltaRotation(oldRotation, rotation) != Surface.ROTATION_180) {
mDisplayContent.mWaitingForConfig = true;
}
@@ -788,8 +789,13 @@ public class DisplayRotation {
mFixedToUserRotation = fixedToUserRotation;
mDisplayWindowSettings.setFixedToUserRotation(mDisplayContent, fixedToUserRotation);
- mService.updateRotation(true /* alwaysSendConfiguration */,
- false /* forceRelayout */);
+ if (mDisplayContent.mFocusedApp != null) {
+ // We record the last focused TDA that respects orientation request, check if this
+ // change may affect it.
+ mDisplayContent.onLastFocusedTaskDisplayAreaChanged(
+ mDisplayContent.mFocusedApp.getDisplayArea());
+ }
+ mDisplayContent.updateOrientation();
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedTaskDividerController.java
index de4bdaa57efa..fb9d06441536 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedTaskDividerController.java
@@ -19,16 +19,16 @@ package com.android.server.wm;
import android.graphics.Rect;
/**
- * Keeps information about the docked stack divider.
+ * Keeps information about the docked task divider.
*/
-public class DockedStackDividerController {
+public class DockedTaskDividerController {
private final DisplayContent mDisplayContent;
private boolean mResizing;
private final Rect mTouchRegion = new Rect();
- DockedStackDividerController(DisplayContent displayContent) {
+ DockedTaskDividerController(DisplayContent displayContent) {
mDisplayContent = displayContent;
}
@@ -58,6 +58,6 @@ public class DockedStackDividerController {
private void resetDragResizingChangeReported() {
mDisplayContent.forAllWindows(WindowState::resetDragResizingChangeReported,
- true /* traverseTopToBottom */ );
+ true /* traverseTopToBottom */);
}
}
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java
index 8fe2481f9eda..15e078b478b8 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedTaskController.java
@@ -29,18 +29,18 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Slog;
import android.view.DisplayInfo;
-import android.view.IPinnedStackListener;
+import android.view.IPinnedTaskListener;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
/**
- * Holds the common state of the pinned stack between the system and SystemUI. If SystemUI ever
+ * Holds the common state of the pinned task between the system and SystemUI. If SystemUI ever
* needs to be restarted, it will be notified with the last known state.
*
- * Changes to the pinned stack also flow through this controller, and generally, the system only
- * changes the pinned stack bounds through this controller in two ways:
+ * Changes to the pinned task also flow through this controller, and generally, the system only
+ * changes the pinned task bounds through this controller in two ways:
*
* 1) When first entering PiP: the controller returns the valid bounds given, taking aspect ratio
* and IME state into account.
@@ -49,18 +49,18 @@ import java.util.List;
* SystemUI adjustments (ie. expanded for menu, interaction, etc).
*
* Other changes in the system, including adjustment of IME, configuration change, and more are
- * handled by SystemUI (similar to the docked stack divider).
+ * handled by SystemUI (similar to the docked task divider).
*/
-class PinnedStackController {
+class PinnedTaskController {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "PinnedStackController" : TAG_WM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "PinnedTaskController" : TAG_WM;
private final WindowManagerService mService;
private final DisplayContent mDisplayContent;
- private IPinnedStackListener mPinnedStackListener;
- private final PinnedStackListenerDeathHandler mPinnedStackListenerDeathHandler =
- new PinnedStackListenerDeathHandler();
+ private IPinnedTaskListener mPinnedTaskListener;
+ private final PinnedTaskListenerDeathHandler mPinnedTaskListenerDeathHandler =
+ new PinnedTaskListenerDeathHandler();
/** Whether the PiP is entering or leaving. */
private boolean mIsPipWindowingModeChanging;
@@ -72,7 +72,7 @@ class PinnedStackController {
private ArrayList<RemoteAction> mActions = new ArrayList<>();
private float mAspectRatio = -1f;
- // Used to calculate stack bounds across rotations
+ // Used to calculate task bounds across rotations
private final DisplayInfo mDisplayInfo = new DisplayInfo();
// The aspect ratio bounds of the PIP.
@@ -85,19 +85,19 @@ class PinnedStackController {
/**
* Handler for the case where the listener dies.
*/
- private class PinnedStackListenerDeathHandler implements IBinder.DeathRecipient {
+ private class PinnedTaskListenerDeathHandler implements IBinder.DeathRecipient {
@Override
public void binderDied() {
// Clean up the state if the listener dies
- if (mPinnedStackListener != null) {
- mPinnedStackListener.asBinder().unlinkToDeath(mPinnedStackListenerDeathHandler, 0);
+ if (mPinnedTaskListener != null) {
+ mPinnedTaskListener.asBinder().unlinkToDeath(mPinnedTaskListenerDeathHandler, 0);
}
- mPinnedStackListener = null;
+ mPinnedTaskListener = null;
}
}
- PinnedStackController(WindowManagerService service, DisplayContent displayContent) {
+ PinnedTaskController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
mDisplayContent = displayContent;
mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
@@ -121,17 +121,17 @@ class PinnedStackController {
}
/**
- * Registers a pinned stack listener.
+ * Registers a pinned task listener.
*/
- void registerPinnedStackListener(IPinnedStackListener listener) {
+ void registerPinnedTaskListener(IPinnedTaskListener listener) {
try {
- listener.asBinder().linkToDeath(mPinnedStackListenerDeathHandler, 0);
- mPinnedStackListener = listener;
+ listener.asBinder().linkToDeath(mPinnedTaskListenerDeathHandler, 0);
+ mPinnedTaskListener = listener;
notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
notifyMovementBoundsChanged(false /* fromImeAdjustment */);
notifyActionsChanged(mActions);
} catch (RemoteException e) {
- Log.e(TAG, "Failed to register pinned stack listener", e);
+ Log.e(TAG, "Failed to register pinned task listener", e);
}
}
@@ -139,8 +139,8 @@ class PinnedStackController {
* @return whether the given {@param aspectRatio} is valid.
*/
public boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
- return Float.compare(mMinAspectRatio, aspectRatio) <= 0 &&
- Float.compare(aspectRatio, mMaxAspectRatio) <= 0;
+ return Float.compare(mMinAspectRatio, aspectRatio) <= 0
+ && Float.compare(aspectRatio, mMaxAspectRatio) <= 0;
}
/** Returns {@code true} if the PiP is on screen or is changing windowing mode. */
@@ -152,7 +152,7 @@ class PinnedStackController {
return pinnedTask != null && pinnedTask.hasChild();
}
- /** Sets whether a visible stack is changing from or to pinned mode. */
+ /** Sets whether a visible task is changing from or to pinned mode. */
void setPipWindowingModeChanging(boolean isPipWindowingModeChanging) {
mIsPipWindowingModeChanging = isPipWindowingModeChanging;
}
@@ -162,9 +162,9 @@ class PinnedStackController {
* so that the default bounds will be returned for the next session.
*/
void onActivityHidden(ComponentName componentName) {
- if (mPinnedStackListener == null) return;
+ if (mPinnedTaskListener == null) return;
try {
- mPinnedStackListener.onActivityHidden(componentName);
+ mPinnedTaskListener.onActivityHidden(componentName);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering reset reentry fraction event.", e);
}
@@ -223,9 +223,9 @@ class PinnedStackController {
* Notifies listeners that the PIP needs to be adjusted for the IME.
*/
private void notifyImeVisibilityChanged(boolean imeVisible, int imeHeight) {
- if (mPinnedStackListener != null) {
+ if (mPinnedTaskListener != null) {
try {
- mPinnedStackListener.onImeVisibilityChanged(imeVisible, imeHeight);
+ mPinnedTaskListener.onImeVisibilityChanged(imeVisible, imeHeight);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering bounds changed event.", e);
}
@@ -233,9 +233,9 @@ class PinnedStackController {
}
private void notifyAspectRatioChanged(float aspectRatio) {
- if (mPinnedStackListener == null) return;
+ if (mPinnedTaskListener == null) return;
try {
- mPinnedStackListener.onAspectRatioChanged(aspectRatio);
+ mPinnedTaskListener.onAspectRatioChanged(aspectRatio);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering aspect ratio changed event.", e);
}
@@ -245,9 +245,9 @@ class PinnedStackController {
* Notifies listeners that the PIP actions have changed.
*/
private void notifyActionsChanged(List<RemoteAction> actions) {
- if (mPinnedStackListener != null) {
+ if (mPinnedTaskListener != null) {
try {
- mPinnedStackListener.onActionsChanged(new ParceledListSlice(actions));
+ mPinnedTaskListener.onActionsChanged(new ParceledListSlice(actions));
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering actions changed event.", e);
}
@@ -259,11 +259,11 @@ class PinnedStackController {
*/
private void notifyMovementBoundsChanged(boolean fromImeAdjustment) {
synchronized (mService.mGlobalLock) {
- if (mPinnedStackListener == null) {
+ if (mPinnedTaskListener == null) {
return;
}
try {
- mPinnedStackListener.onMovementBoundsChanged(fromImeAdjustment);
+ mPinnedTaskListener.onMovementBoundsChanged(fromImeAdjustment);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering actions changed event.", e);
}
@@ -271,7 +271,7 @@ class PinnedStackController {
}
void dump(String prefix, PrintWriter pw) {
- pw.println(prefix + "PinnedStackController");
+ pw.println(prefix + "PinnedTaskController");
pw.println(prefix + " mIsImeShowing=" + mIsImeShowing);
pw.println(prefix + " mImeHeight=" + mImeHeight);
pw.println(prefix + " mAspectRatio=" + mAspectRatio);
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 533c82e599c9..95a4f69edd57 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.util.RotationUtils.deltaRotation;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
@@ -174,7 +175,7 @@ class ScreenRotationAnimation {
// apply rotation animation because there should be a top app shown as rotated. So the
// specified original rotation customizes the direction of animation to have better look
// when restoring the rotated app to the same rotation as current display.
- final int delta = DisplayContent.deltaRotation(originalRotation, realOriginalRotation);
+ final int delta = deltaRotation(originalRotation, realOriginalRotation);
final boolean flipped = delta == Surface.ROTATION_90 || delta == Surface.ROTATION_270;
mOriginalWidth = flipped ? originalHeight : originalWidth;
mOriginalHeight = flipped ? originalWidth : originalHeight;
@@ -330,7 +331,7 @@ class ScreenRotationAnimation {
// Compute the transformation matrix that must be applied
// to the snapshot to make it stay in the same original position
// with the current screen rotation.
- int delta = DisplayContent.deltaRotation(rotation, Surface.ROTATION_0);
+ int delta = deltaRotation(rotation, Surface.ROTATION_0);
RotationAnimationUtils.createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
setRotationTransform(t, mSnapshotInitialMatrix);
@@ -352,8 +353,7 @@ class ScreenRotationAnimation {
mStarted = true;
// Figure out how the screen has moved from the original rotation.
- int delta = DisplayContent.deltaRotation(mCurRotation, mOriginalRotation);
-
+ int delta = deltaRotation(mCurRotation, mOriginalRotation);
final boolean customAnim;
if (exitAnim != 0 && enterAnim != 0) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index d60b6e0ef81d..29c7ff118595 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2267,7 +2267,7 @@ class Task extends WindowContainer<WindowContainer> {
}
if (pipChanging) {
- mDisplayContent.getPinnedStackController().setPipWindowingModeChanging(true);
+ mDisplayContent.getPinnedTaskController().setPipWindowingModeChanging(true);
// If the top activity is using fixed rotation, it should be changing from PiP to
// fullscreen with display orientation change. Do not notify fullscreen task organizer
// because the restoration of task surface and the transformation of activity surface
@@ -2297,7 +2297,7 @@ class Task extends WindowContainer<WindowContainer> {
}
} finally {
if (pipChanging) {
- mDisplayContent.getPinnedStackController().setPipWindowingModeChanging(false);
+ mDisplayContent.getPinnedTaskController().setPipWindowingModeChanging(false);
}
}
@@ -2361,9 +2361,7 @@ class Task extends WindowContainer<WindowContainer> {
final int newRotation = getWindowConfiguration().getRotation();
final boolean rotationChanged = prevRotation != newRotation;
if (rotationChanged) {
- mDisplayContent.rotateBounds(
- newParentConfig.windowConfiguration.getBounds(), prevRotation, newRotation,
- newBounds);
+ mDisplayContent.rotateBounds(prevRotation, newRotation, newBounds);
setBounds(newBounds);
}
}
@@ -7792,18 +7790,18 @@ class Task extends WindowContainer<WindowContainer> {
return;
}
- final PinnedStackController pinnedStackController =
- getDisplayContent().getPinnedStackController();
+ final PinnedTaskController pinnedTaskController =
+ getDisplayContent().getPinnedTaskController();
- if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) == 0) {
+ if (Float.compare(aspectRatio, pinnedTaskController.getAspectRatio()) == 0) {
return;
}
// Notify the pinned stack controller about aspect ratio change.
// This would result a callback delivered from SystemUI to WM to start animation,
// if the bounds are ought to be altered due to aspect ratio change.
- pinnedStackController.setAspectRatio(
- pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
+ pinnedTaskController.setAspectRatio(
+ pinnedTaskController.isValidPictureInPictureAspectRatio(aspectRatio)
? aspectRatio : -1f);
}
@@ -7819,7 +7817,7 @@ class Task extends WindowContainer<WindowContainer> {
return;
}
- getDisplayContent().getPinnedStackController().setActions(actions);
+ getDisplayContent().getPinnedTaskController().setActions(actions);
}
/** Returns true if a removal action is still being deferred. */
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index 9b7257057836..04ec4bd83511 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -130,8 +130,8 @@ class TaskChangeNotificationController {
l.onActivityForcedResizable((String) m.obj, m.arg1, m.arg2);
};
- private final TaskStackConsumer mNotifyActivityDismissingDockedStack = (l, m) -> {
- l.onActivityDismissingDockedStack();
+ private final TaskStackConsumer mNotifyActivityDismissingDockedTask = (l, m) -> {
+ l.onActivityDismissingDockedTask();
};
private final TaskStackConsumer mNotifyActivityLaunchOnSecondaryDisplayFailed = (l, m) -> {
@@ -235,7 +235,7 @@ class TaskChangeNotificationController {
forAllRemoteListeners(mNotifyActivityForcedResizable, msg);
break;
case NOTIFY_ACTIVITY_DISMISSING_DOCKED_ROOT_TASK_MSG:
- forAllRemoteListeners(mNotifyActivityDismissingDockedStack, msg);
+ forAllRemoteListeners(mNotifyActivityDismissingDockedTask, msg);
break;
case NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG:
forAllRemoteListeners(mNotifyActivityLaunchOnSecondaryDisplayFailed, msg);
@@ -391,7 +391,7 @@ class TaskChangeNotificationController {
void notifyActivityDismissingDockedRootTask() {
mHandler.removeMessages(NOTIFY_ACTIVITY_DISMISSING_DOCKED_ROOT_TASK_MSG);
final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_DISMISSING_DOCKED_ROOT_TASK_MSG);
- forAllLocalListeners(mNotifyActivityDismissingDockedStack, msg);
+ forAllLocalListeners(mNotifyActivityDismissingDockedTask, msg);
msg.sendToTarget();
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index c0bce6be8c54..1531e56bf490 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -596,9 +596,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
try {
synchronized (mGlobalLock) {
final WindowContainer wc = WindowContainer.fromBinder(token.asBinder());
- if (wc == null) {
- throw new IllegalArgumentException("Can't resolve window from token");
- }
+ if (wc == null) return false;
final Task task = wc.asTask();
if (task == null) return false;
if (!task.mCreatedByOrganizer) {
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index 361694b325f9..9245f8c3efe5 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static com.android.server.wm.WindowFramesProto.COMPAT_FRAME;
import static com.android.server.wm.WindowFramesProto.CONTAINING_FRAME;
import static com.android.server.wm.WindowFramesProto.DISPLAY_FRAME;
import static com.android.server.wm.WindowFramesProto.FRAME;
@@ -177,7 +178,7 @@ public class WindowFrames {
mDisplayFrame.dumpDebug(proto, DISPLAY_FRAME);
mContainingFrame.dumpDebug(proto, CONTAINING_FRAME);
mFrame.dumpDebug(proto, FRAME);
-
+ mCompatFrame.dumpDebug(proto, COMPAT_FRAME);
proto.end(token);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 89d30408fe25..71d2b2f7b882 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -230,7 +230,7 @@ import android.view.IDisplayWindowListener;
import android.view.IDisplayWindowRotationController;
import android.view.IInputFilter;
import android.view.IOnKeyguardExitResult;
-import android.view.IPinnedStackListener;
+import android.view.IPinnedTaskListener;
import android.view.IRecentsAnimationRunner;
import android.view.IRotationWatcher;
import android.view.IScrollCaptureCallbacks;
@@ -2981,7 +2981,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
boolean isValidPictureInPictureAspectRatio(DisplayContent displayContent, float aspectRatio) {
- return displayContent.getPinnedStackController().isValidPictureInPictureAspectRatio(
+ return displayContent.getPinnedTaskController().isValidPictureInPictureAspectRatio(
aspectRatio);
}
@@ -6880,7 +6880,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void setDockedStackDividerTouchRegion(Rect touchRegion) {
+ public void setDockedTaskDividerTouchRegion(Rect touchRegion) {
synchronized (mGlobalLock) {
final DisplayContent dc = getDefaultDisplayContentLocked();
dc.getDockedDividerController().setTouchRegion(touchRegion);
@@ -6905,10 +6905,9 @@ public class WindowManagerService extends IWindowManager.Stub
return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics);
}
- @Override
- public void registerPinnedStackListener(int displayId, IPinnedStackListener listener) {
+ public void registerPinnedTaskListener(int displayId, IPinnedTaskListener listener) {
if (!checkCallingPermission(REGISTER_WINDOW_MANAGER_LISTENERS,
- "registerPinnedStackListener()")) {
+ "registerPinnedTaskListener()")) {
return;
}
if (!mAtmService.mSupportsPictureInPicture) {
@@ -6916,7 +6915,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
- displayContent.getPinnedStackController().registerPinnedStackListener(listener);
+ displayContent.getPinnedTaskController().registerPinnedTaskListener(listener);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 63a083261614..9973664346f0 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import static android.Manifest.permission.READ_FRAME_BUFFER;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT;
@@ -426,8 +425,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
if (windowingMode > -1) {
- if (mService.isInLockTaskMode() && windowingMode != WINDOWING_MODE_FULLSCREEN) {
- throw new UnsupportedOperationException("Not supported to set non-fullscreen"
+ if (mService.isInLockTaskMode()
+ && WindowConfiguration.inMultiWindowMode(windowingMode)) {
+ throw new UnsupportedOperationException("Not supported to set multi-window"
+ " windowing mode during locked task mode.");
}
container.setWindowingMode(windowingMode);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3dfdedfec0d1..9ae5beb625f8 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -169,7 +169,9 @@ import static com.android.server.wm.WindowStateProto.DISPLAY_ID;
import static com.android.server.wm.WindowStateProto.FINISHED_SEAMLESS_ROTATION_FRAME;
import static com.android.server.wm.WindowStateProto.FORCE_SEAMLESS_ROTATION;
import static com.android.server.wm.WindowStateProto.GIVEN_CONTENT_INSETS;
+import static com.android.server.wm.WindowStateProto.GLOBAL_SCALE;
import static com.android.server.wm.WindowStateProto.HAS_SURFACE;
+import static com.android.server.wm.WindowStateProto.IN_SIZE_COMPAT_MODE;
import static com.android.server.wm.WindowStateProto.IS_ON_SCREEN;
import static com.android.server.wm.WindowStateProto.IS_READY_FOR_DISPLAY;
import static com.android.server.wm.WindowStateProto.IS_VISIBLE;
@@ -1222,7 +1224,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// But in docked we want to behave like fullscreen and behave as if the task
// were given smaller bounds for the purposes of layout. Skip adjustments for
// the root pinned task, they are handled separately in the
- // PinnedStackController.
+ // PinnedTaskController.
windowFrames.mContainingFrame.bottom = windowFrames.mParentFrame.bottom;
}
}
@@ -4002,6 +4004,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
proto.write(PENDING_SEAMLESS_ROTATION, mPendingSeamlessRotate != null);
proto.write(FINISHED_SEAMLESS_ROTATION_FRAME, mFinishSeamlessRotateFrameNumber);
proto.write(FORCE_SEAMLESS_ROTATION, mForceSeamlesslyRotate);
+ proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode());
+ proto.write(GLOBAL_SCALE, mGlobalScale);
proto.end(token);
}
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index 4551d49d9e58..f054e7c73015 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -86,7 +86,7 @@ static int compactMemory(const std::vector<Vma>& vmas, int pid, int madviseType)
int pidfd = syscall(__NR_pidfd_open, pid, 0);
err = -errno;
- if (err < 0) {
+ if (pidfd < 0) {
// Skip compaction if failed to open pidfd with any error
return err;
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 840e119de477..10705af9ac38 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -158,6 +158,20 @@ static struct {
static struct {
jclass clazz;
jmethodID constructor;
+ jfieldID lightTypeSingle;
+ jfieldID lightTypePlayerId;
+ jfieldID lightTypeRgb;
+} gLightClassInfo;
+
+static struct {
+ jclass clazz;
+ jmethodID constructor;
+ jmethodID add;
+} gArrayListClassInfo;
+
+static struct {
+ jclass clazz;
+ jmethodID constructor;
jmethodID keyAt;
jmethodID valueAt;
jmethodID size;
@@ -1923,6 +1937,79 @@ static jintArray nativeGetVibratorIds(JNIEnv* env, jclass clazz, jlong ptr, jint
return vibIdArray;
}
+static jobject nativeGetLights(JNIEnv* env, jclass clazz, jlong ptr, jint deviceId) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+ jobject jLights = env->NewObject(gArrayListClassInfo.clazz, gArrayListClassInfo.constructor);
+
+ std::vector<int> lightIds = im->getInputManager()->getReader()->getLightIds(deviceId);
+
+ for (size_t i = 0; i < lightIds.size(); i++) {
+ const InputDeviceLightInfo* lightInfo =
+ im->getInputManager()->getReader()->getLightInfo(deviceId, lightIds[i]);
+ if (lightInfo == nullptr) {
+ ALOGW("Failed to get input device %d light info for id %d", deviceId, lightIds[i]);
+ continue;
+ }
+
+ jint jTypeId = 0;
+ if (lightInfo->type == InputDeviceLightType::SINGLE) {
+ jTypeId =
+ env->GetStaticIntField(gLightClassInfo.clazz, gLightClassInfo.lightTypeSingle);
+ } else if (lightInfo->type == InputDeviceLightType::PLAYER_ID) {
+ jTypeId = env->GetStaticIntField(gLightClassInfo.clazz,
+ gLightClassInfo.lightTypePlayerId);
+ } else if (lightInfo->type == InputDeviceLightType::RGB ||
+ lightInfo->type == InputDeviceLightType::MULTI_COLOR) {
+ jTypeId = env->GetStaticIntField(gLightClassInfo.clazz, gLightClassInfo.lightTypeRgb);
+ } else {
+ ALOGW("Unknown light type %d", lightInfo->type);
+ continue;
+ }
+ ScopedLocalRef<jobject>
+ lightObj(env,
+ env->NewObject(gLightClassInfo.clazz, gLightClassInfo.constructor,
+ (jint)lightInfo->id, (jint)lightInfo->ordinal, jTypeId,
+ env->NewStringUTF(lightInfo->name.c_str())));
+ // Add light object to list
+ env->CallBooleanMethod(jLights, gArrayListClassInfo.add, lightObj.get());
+ }
+
+ return jLights;
+}
+
+static jint nativeGetLightPlayerId(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId,
+ jint lightId) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ std::optional<int32_t> ret =
+ im->getInputManager()->getReader()->getLightPlayerId(deviceId, lightId);
+
+ return static_cast<jint>(ret.value_or(0));
+}
+
+static jint nativeGetLightColor(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId,
+ jint lightId) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ std::optional<int32_t> ret =
+ im->getInputManager()->getReader()->getLightColor(deviceId, lightId);
+ return static_cast<jint>(ret.value_or(0));
+}
+
+static void nativeSetLightPlayerId(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId,
+ jint lightId, jint playerId) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->getInputManager()->getReader()->setLightPlayerId(deviceId, lightId, playerId);
+}
+
+static void nativeSetLightColor(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId,
+ jint lightId, jint color) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->getInputManager()->getReader()->setLightColor(deviceId, lightId, color);
+}
+
static jint nativeGetBatteryCapacity(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
@@ -2192,6 +2279,11 @@ static const JNINativeMethod gInputManagerMethods[] = {
{"nativeCancelVibrate", "(JII)V", (void*)nativeCancelVibrate},
{"nativeIsVibrating", "(JI)Z", (void*)nativeIsVibrating},
{"nativeGetVibratorIds", "(JI)[I", (void*)nativeGetVibratorIds},
+ {"nativeGetLights", "(JI)Ljava/util/List;", (void*)nativeGetLights},
+ {"nativeGetLightPlayerId", "(JII)I", (void*)nativeGetLightPlayerId},
+ {"nativeGetLightColor", "(JII)I", (void*)nativeGetLightColor},
+ {"nativeSetLightPlayerId", "(JIII)V", (void*)nativeSetLightPlayerId},
+ {"nativeSetLightColor", "(JIII)V", (void*)nativeSetLightColor},
{"nativeGetBatteryCapacity", "(JI)I", (void*)nativeGetBatteryCapacity},
{"nativeGetBatteryStatus", "(JI)I", (void*)nativeGetBatteryStatus},
{"nativeReloadKeyboardLayouts", "(J)V", (void*)nativeReloadKeyboardLayouts},
@@ -2386,6 +2478,27 @@ int register_android_server_InputManager(JNIEnv* env) {
GET_METHOD_ID(gTouchCalibrationClassInfo.getAffineTransform, gTouchCalibrationClassInfo.clazz,
"getAffineTransform", "()[F");
+ // Light
+ FIND_CLASS(gLightClassInfo.clazz, "android/hardware/lights/Light");
+ gLightClassInfo.clazz = jclass(env->NewGlobalRef(gLightClassInfo.clazz));
+ GET_METHOD_ID(gLightClassInfo.constructor, gLightClassInfo.clazz, "<init>",
+ "(IIILjava/lang/String;)V");
+
+ gLightClassInfo.clazz = jclass(env->NewGlobalRef(gLightClassInfo.clazz));
+ gLightClassInfo.lightTypeSingle =
+ env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_TYPE_INPUT_SINGLE", "I");
+ gLightClassInfo.lightTypePlayerId =
+ env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_TYPE_INPUT_PLAYER_ID", "I");
+ gLightClassInfo.lightTypeRgb =
+ env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_TYPE_INPUT_RGB", "I");
+
+ // ArrayList
+ FIND_CLASS(gArrayListClassInfo.clazz, "java/util/ArrayList");
+ gArrayListClassInfo.clazz = jclass(env->NewGlobalRef(gArrayListClassInfo.clazz));
+ GET_METHOD_ID(gArrayListClassInfo.constructor, gArrayListClassInfo.clazz, "<init>", "()V");
+ GET_METHOD_ID(gArrayListClassInfo.add, gArrayListClassInfo.clazz, "add",
+ "(Ljava/lang/Object;)Z");
+
// SparseArray
FIND_CLASS(gSparseArrayClassInfo.clazz, "android/util/SparseArray");
gSparseArrayClassInfo.clazz = jclass(env->NewGlobalRef(gSparseArrayClassInfo.clazz));
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index b52347f509f8..ef7afc8d1894 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -129,6 +129,15 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
FullyManagedDeviceProvisioningParams provisioningParams, String callerPackage) {
}
+ @Override
+ public void setDeviceOwnerType(@NonNull ComponentName admin, int deviceOwnerType) {
+ }
+
+ @Override
+ public int getDeviceOwnerType(@NonNull ComponentName admin) {
+ return 0;
+ }
+
public void resetDefaultCrossProfileIntentFilters(@UserIdInt int userId) {}
public boolean canAdminGrantSensorsPermissionsForUser(int userId) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7260732bbcb6..524892b2ec4b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -156,6 +156,7 @@ import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyCache;
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.DeviceOwnerType;
import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
import android.app.admin.DevicePolicyManager.OperationSafetyReason;
import android.app.admin.DevicePolicyManager.PasswordComplexity;
@@ -333,6 +334,7 @@ import com.google.android.collect.Sets;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -340,6 +342,9 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
import java.text.DateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
@@ -3399,8 +3404,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(adminReceiver, "ComponentName is null");
- Preconditions.checkCallAuthorization(isAdb(getCallerIdentity()),
- "Non-shell user attempted to call forceRemoveActiveAdmin");
+ Preconditions.checkCallAuthorization(isAdb(getCallerIdentity())
+ || hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS),
+ "Caller must be shell or hold MANAGE_PROFILE_AND_DEVICE_OWNERS to call "
+ + "forceRemoveActiveAdmin");
mInjector.binderWithCleanCallingIdentity(() -> {
synchronized (getLockObject()) {
if (!isAdminTestOnlyLocked(adminReceiver, userHandle)) {
@@ -5622,7 +5629,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// Get attestation flags, if any.
final int[] attestationUtilsFlags = translateIdAttestationFlags(idAttestationFlags);
final boolean deviceIdAttestationRequired = attestationUtilsFlags != null;
- final KeyGenParameterSpec keySpec = parcelableKeySpec.getSpec();
+ KeyGenParameterSpec keySpec = parcelableKeySpec.getSpec();
final String alias = keySpec.getKeystoreAlias();
Preconditions.checkStringNotEmpty(alias, "Empty alias provided");
@@ -5643,6 +5650,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|| (caller.hasPackage() && (isCallerDelegate || isCredentialManagementApp)));
}
+ if (TextUtils.isEmpty(alias)) {
+ throw new IllegalArgumentException("Empty alias provided.");
+ }
// As the caller will be granted access to the key, ensure no UID was specified, as
// it will not have the desired effect.
if (keySpec.getUid() != KeyStore.UID_SELF) {
@@ -5651,19 +5661,26 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
+ if (deviceIdAttestationRequired) {
+ if (keySpec.getAttestationChallenge() == null) {
+ throw new IllegalArgumentException(
+ "Requested Device ID attestation but challenge is empty.");
+ }
+ KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder(keySpec);
+ specBuilder.setAttestationIds(attestationUtilsFlags);
+ specBuilder.setDevicePropertiesAttestationIncluded(true);
+ keySpec = specBuilder.build();
+ }
+
+ final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
final long id = mInjector.binderClearCallingIdentity();
try {
try (KeyChainConnection keyChainConnection =
- KeyChain.bindAsUser(mContext, caller.getUserHandle())) {
+ KeyChain.bindAsUser(mContext, userHandle)) {
IKeyChainService keyChain = keyChainConnection.getService();
- // Copy the provided keySpec, excluding the attestation challenge, which will be
- // used later for requesting key attestation record.
- final KeyGenParameterSpec noAttestationSpec = new KeyGenParameterSpec.Builder(
- keySpec).setAttestationChallenge(null).build();
-
final int generationResult = keyChain.generateKeyPair(algorithm,
- new ParcelableKeyGenParameterSpec(noAttestationSpec));
+ new ParcelableKeyGenParameterSpec(keySpec));
if (generationResult != KeyChain.KEY_GEN_SUCCESS) {
Log.e(LOG_TAG, String.format(
"KeyChain failed to generate a keypair, error %d.", generationResult));
@@ -5672,6 +5689,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
throw new ServiceSpecificException(
DevicePolicyManager.KEY_GEN_STRONGBOX_UNAVAILABLE,
String.format("KeyChain error: %d", generationResult));
+ case KeyChain.KEY_ATTESTATION_CANNOT_ATTEST_IDS:
+ throw new UnsupportedOperationException(
+ "Device does not support Device ID attestation.");
default:
logGenerateKeyPairFailure(caller, isCredentialManagementApp);
return false;
@@ -5685,23 +5705,27 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// that UID.
keyChain.setGrant(caller.getUid(), alias, true);
- final byte[] attestationChallenge = keySpec.getAttestationChallenge();
- if (attestationChallenge != null) {
- final int attestationResult = keyChain.attestKey(
- alias, attestationChallenge, attestationUtilsFlags, attestationChain);
- if (attestationResult != KeyChain.KEY_ATTESTATION_SUCCESS) {
- Log.e(LOG_TAG, String.format(
- "Attestation for %s failed (rc=%d), deleting key.",
- alias, attestationResult));
- keyChain.removeKeyPair(alias);
- if (attestationResult == KeyChain.KEY_ATTESTATION_CANNOT_ATTEST_IDS) {
- throw new UnsupportedOperationException(
- "Device does not support Device ID attestation.");
+ try {
+ final List<byte[]> encodedCerts = new ArrayList();
+ final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+ final byte[] certChainBytes = keyChain.getCaCertificates(alias);
+ encodedCerts.add(keyChain.getCertificate(alias));
+ if (certChainBytes != null) {
+ final Collection<X509Certificate> certs =
+ (Collection<X509Certificate>) certFactory.generateCertificates(
+ new ByteArrayInputStream(certChainBytes));
+ for (X509Certificate cert : certs) {
+ encodedCerts.add(cert.getEncoded());
}
- logGenerateKeyPairFailure(caller, isCredentialManagementApp);
- return false;
}
+
+ attestationChain.shallowCopyFrom(new KeymasterCertificateChain(encodedCerts));
+ } catch (CertificateException e) {
+ logGenerateKeyPairFailure(caller, isCredentialManagementApp);
+ Log.e(LOG_TAG, "While retrieving certificate chain.", e);
+ return false;
}
+
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.GENERATE_KEY_PAIR)
.setAdmin(caller.getPackageName())
@@ -7560,8 +7584,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
private void sendProfileOwnerCommand(String action, Bundle extras, @UserIdInt int userId) {
- sendActiveAdminCommand(action, extras, userId,
- mOwners.getProfileOwnerComponent(userId));
+ sendActiveAdminCommand(action, extras, userId, mOwners.getProfileOwnerComponent(userId));
}
private void sendActiveAdminCommand(String action, Bundle extras,
@@ -8089,7 +8112,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
if (!callingUserOnly) {
- Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+ Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity())
+ || hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
}
synchronized (getLockObject()) {
if (!mOwners.hasDeviceOwner()) {
@@ -12351,8 +12375,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
extras.putInt(DeviceAdminReceiver.EXTRA_OPERATION_SAFETY_REASON, reason);
extras.putBoolean(DeviceAdminReceiver.EXTRA_OPERATION_SAFETY_STATE, isSafe);
- sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED,
- extras);
+ if (mOwners.hasDeviceOwner()) {
+ sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED,
+ extras);
+ }
for (int profileOwnerId : mOwners.getProfileOwnerKeys()) {
sendProfileOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED,
extras, profileOwnerId);
@@ -12543,8 +12569,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void clearSystemUpdatePolicyFreezePeriodRecord() {
- Preconditions.checkCallAuthorization(isAdb(getCallerIdentity()),
- "Non-shell user attempted to call clearSystemUpdatePolicyFreezePeriodRecord");
+ Preconditions.checkCallAuthorization(isAdb(getCallerIdentity())
+ || hasCallingOrSelfPermission(permission.CLEAR_FREEZE_PERIOD),
+ "Caller must be shell, or hold CLEAR_FREEZE_PERIOD permission to call "
+ + "clearSystemUpdatePolicyFreezePeriodRecord");
synchronized (getLockObject()) {
// Print out current record to help diagnosed CTS failures
Slog.i(LOG_TAG, "Clear freeze period record: "
@@ -13487,7 +13515,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final CallerIdentity caller = getCallerIdentity();
// Only adb or system apps with the right permission can mark a profile owner on
// organization-owned device.
- if (!(isAdb(caller) || hasCallingPermission(permission.MARK_DEVICE_ORGANIZATION_OWNED))) {
+ if (!(isAdb(caller) || hasCallingPermission(permission.MARK_DEVICE_ORGANIZATION_OWNED)
+ || hasCallingPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS))) {
throw new SecurityException(
"Only the system can mark a profile owner of organization-owned device.");
}
@@ -13806,8 +13835,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public long forceSecurityLogs() {
- Preconditions.checkCallAuthorization(isAdb(getCallerIdentity()),
- "Non-shell user attempted to call forceSecurityLogs");
+ Preconditions.checkCallAuthorization(isAdb(getCallerIdentity())
+ || hasCallingOrSelfPermission(permission.FORCE_DEVICE_POLICY_MANAGER_LOGS),
+ "Caller must be shell or hold FORCE_DEVICE_POLICY_MANAGER_LOGS to call "
+ + "forceSecurityLogs");
if (!mInjector.securityLogGetLoggingEnabledProperty()) {
throw new IllegalStateException("logging is not available");
}
@@ -14327,8 +14358,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public long forceNetworkLogs() {
- Preconditions.checkCallAuthorization(isAdb(getCallerIdentity()),
- "Non-shell user attempted to call forceNetworkLogs");
+ Preconditions.checkCallAuthorization(isAdb(getCallerIdentity())
+ || hasCallingOrSelfPermission(permission.FORCE_DEVICE_POLICY_MANAGER_LOGS),
+ "Caller must be shell or hold FORCE_DEVICE_POLICY_MANAGER_LOGS to call "
+ + "forceNetworkLogs");
synchronized (getLockObject()) {
if (!isNetworkLoggingEnabledInternalLocked()) {
throw new IllegalStateException("logging is not available");
@@ -16731,6 +16764,37 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
+ public void setDeviceOwnerType(@NonNull ComponentName admin,
+ @DeviceOwnerType int deviceOwnerType) {
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+ permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+ verifyDeviceOwnerTypePreconditions(admin);
+
+ final String packageName = admin.getPackageName();
+ Preconditions.checkState(!mOwners.isDeviceOwnerTypeSetForDeviceOwner(packageName),
+ "The device owner type has already been set for " + packageName);
+
+ synchronized (getLockObject()) {
+ mOwners.setDeviceOwnerType(packageName, deviceOwnerType);
+ }
+ }
+
+ @Override
+ @DeviceOwnerType
+ public int getDeviceOwnerType(@NonNull ComponentName admin) {
+ verifyDeviceOwnerTypePreconditions(admin);
+ synchronized (getLockObject()) {
+ return mOwners.getDeviceOwnerType(admin.getPackageName());
+ }
+ }
+
+ private void verifyDeviceOwnerTypePreconditions(@NonNull ComponentName admin) {
+ Preconditions.checkState(mOwners.hasDeviceOwner(), "there is no device owner");
+ Preconditions.checkState(mOwners.getDeviceOwnerComponent().equals(admin),
+ "admin is not the device owner");
+ }
+
+ @Override
public void setUsbDataSignalingEnabled(String packageName, boolean enabled) {
Objects.requireNonNull(packageName, "Admin package name must be provided");
final CallerIdentity caller = getCallerIdentity(packageName);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
index 776b44445678..257fc640f93c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
@@ -23,6 +23,8 @@ import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
import android.app.admin.DevicePolicyManager.OperationSafetyReason;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DevicePolicySafetyChecker;
+import android.os.Handler;
+import android.os.Looper;
import android.util.Slog;
import com.android.internal.os.IResultReceiver;
@@ -42,10 +44,15 @@ final class OneTimeSafetyChecker implements DevicePolicySafetyChecker {
private static final String TAG = OneTimeSafetyChecker.class.getSimpleName();
+ private static final long SELF_DESTRUCT_TIMEOUT_MS = 10_000;
+
private final DevicePolicyManagerService mService;
private final DevicePolicySafetyChecker mRealSafetyChecker;
private final @DevicePolicyOperation int mOperation;
private final @OperationSafetyReason int mReason;
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+ private boolean mDone;
OneTimeSafetyChecker(DevicePolicyManagerService service,
@DevicePolicyOperation int operation, @OperationSafetyReason int reason) {
@@ -53,7 +60,11 @@ final class OneTimeSafetyChecker implements DevicePolicySafetyChecker {
mOperation = operation;
mReason = reason;
mRealSafetyChecker = service.getDevicePolicySafetyChecker();
- Slog.i(TAG, "Saving real DevicePolicySafetyChecker as " + mRealSafetyChecker);
+ Slog.i(TAG, "OneTimeSafetyChecker constructor: operation= " + operationToString(operation)
+ + ", reason=" + operationSafetyReasonToString(reason)
+ + ", realChecker=" + mRealSafetyChecker
+ + ", maxDuration=" + SELF_DESTRUCT_TIMEOUT_MS + "ms");
+ mHandler.postDelayed(() -> selfDestruct(), SELF_DESTRUCT_TIMEOUT_MS);
}
@Override
@@ -99,8 +110,21 @@ final class OneTimeSafetyChecker implements DevicePolicySafetyChecker {
}
private void disableSelf() {
+ if (mDone) {
+ Slog.w(TAG, "disableSelf(): already disabled");
+ return;
+ }
Slog.i(TAG, "restoring DevicePolicySafetyChecker to " + mRealSafetyChecker);
mService.setDevicePolicySafetyCheckerUnchecked(mRealSafetyChecker);
+ mDone = true;
+ }
+
+ private void selfDestruct() {
+ if (mDone) return;
+
+ // Usually happens when a CTS failed before calling the DPM method that would clear it
+ Slog.e(TAG, "Self destructing " + this + ", as it was not automatically disabled");
+ disableSelf();
}
@Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 1e70d59a5fd5..7fdd6eeef642 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -16,10 +16,13 @@
package com.android.server.devicepolicy;
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
+
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManagerInternal;
+import android.app.admin.DevicePolicyManager.DeviceOwnerType;
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
import android.content.ComponentName;
@@ -93,6 +96,7 @@ class Owners {
private static final String TAG_PROFILE_OWNER = "profile-owner";
// Holds "context" for device-owner, this must not be show up before device-owner.
private static final String TAG_DEVICE_OWNER_CONTEXT = "device-owner-context";
+ private static final String TAG_DEVICE_OWNER_TYPE = "device-owner-type";
private static final String ATTR_NAME = "name";
private static final String ATTR_PACKAGE = "package";
@@ -109,6 +113,7 @@ class Owners {
// New attribute for profile owner of organization-owned device.
private static final String ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE =
"isPoOrganizationOwnedDevice";
+ private static final String ATTR_DEVICE_OWNER_TYPE_VALUE = "value";
private final UserManager mUserManager;
private final UserManagerInternal mUserManagerInternal;
@@ -121,6 +126,9 @@ class Owners {
// Internal state for the device owner package.
private OwnerInfo mDeviceOwner;
+ // Device owner type for a managed device.
+ private final ArrayMap<String, Integer> mDeviceOwnerTypes = new ArrayMap<>();
+
private int mDeviceOwnerUserId = UserHandle.USER_NULL;
// Internal state for the profile owner packages.
@@ -334,6 +342,7 @@ class Owners {
void clearDeviceOwner() {
synchronized (mLock) {
+ mDeviceOwnerTypes.remove(mDeviceOwner.packageName);
mDeviceOwner = null;
mDeviceOwnerUserId = UserHandle.USER_NULL;
@@ -384,12 +393,16 @@ class Owners {
void transferDeviceOwnership(ComponentName target) {
synchronized (mLock) {
+ Integer previousDeviceOwnerType = mDeviceOwnerTypes.remove(mDeviceOwner.packageName);
// We don't set a name because it's not used anyway.
// See DevicePolicyManagerService#getDeviceOwnerName
mDeviceOwner = new OwnerInfo(null, target,
mDeviceOwner.userRestrictionsMigrated, mDeviceOwner.remoteBugreportUri,
mDeviceOwner.remoteBugreportHash, /* isOrganizationOwnedDevice =*/
mDeviceOwner.isOrganizationOwnedDevice);
+ if (previousDeviceOwnerType != null) {
+ mDeviceOwnerTypes.put(mDeviceOwner.packageName, previousDeviceOwnerType);
+ }
pushToPackageManagerLocked();
pushToActivityTaskManagerLocked();
pushToActivityManagerLocked();
@@ -596,6 +609,37 @@ class Owners {
}
}
+ void setDeviceOwnerType(String packageName, @DeviceOwnerType int deviceOwnerType) {
+ synchronized (mLock) {
+ if (!hasDeviceOwner()) {
+ Slog.e(TAG, "Attempting to set a device owner type when there is no device owner");
+ return;
+ } else if (isDeviceOwnerTypeSetForDeviceOwner(packageName)) {
+ Slog.e(TAG, "Device owner type for " + packageName + " has already been set");
+ return;
+ }
+
+ mDeviceOwnerTypes.put(packageName, deviceOwnerType);
+ writeDeviceOwner();
+ }
+ }
+
+ @DeviceOwnerType
+ int getDeviceOwnerType(String packageName) {
+ synchronized (mLock) {
+ if (isDeviceOwnerTypeSetForDeviceOwner(packageName)) {
+ return mDeviceOwnerTypes.get(packageName);
+ }
+ return DEVICE_OWNER_TYPE_DEFAULT;
+ }
+ }
+
+ boolean isDeviceOwnerTypeSetForDeviceOwner(String packageName) {
+ synchronized (mLock) {
+ return !mDeviceOwnerTypes.isEmpty() && mDeviceOwnerTypes.containsKey(packageName);
+ }
+ }
+
private boolean readLegacyOwnerFileLocked(File file) {
if (!file.exists()) {
// Already migrated or the device has no owners.
@@ -880,6 +924,16 @@ class Owners {
out.startTag(null, TAG_DEVICE_OWNER_CONTEXT);
out.attributeInt(null, ATTR_USERID, mDeviceOwnerUserId);
out.endTag(null, TAG_DEVICE_OWNER_CONTEXT);
+
+ }
+
+ if (!mDeviceOwnerTypes.isEmpty()) {
+ for (ArrayMap.Entry<String, Integer> entry : mDeviceOwnerTypes.entrySet()) {
+ out.startTag(null, TAG_DEVICE_OWNER_TYPE);
+ out.attribute(null, ATTR_PACKAGE, entry.getKey());
+ out.attributeInt(null, ATTR_DEVICE_OWNER_TYPE_VALUE, entry.getValue());
+ out.endTag(null, TAG_DEVICE_OWNER_TYPE);
+ }
}
if (mSystemUpdatePolicy != null) {
@@ -942,6 +996,12 @@ class Owners {
}
}
break;
+ case TAG_DEVICE_OWNER_TYPE:
+ String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+ int deviceOwnerType = parser.getAttributeInt(null, ATTR_DEVICE_OWNER_TYPE_VALUE,
+ DEVICE_OWNER_TYPE_DEFAULT);
+ mDeviceOwnerTypes.put(packageName, deviceOwnerType);
+ break;
default:
Slog.e(TAG, "Unexpected tag: " + tag);
return false;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index dd2dd8150165..6bbd320017a7 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -104,7 +104,6 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.ILockSettings;
import com.android.server.am.ActivityManagerService;
import com.android.server.appbinding.AppBindingService;
-import com.android.server.apphibernation.AppHibernationService;
import com.android.server.attention.AttentionManagerService;
import com.android.server.audio.AudioService;
import com.android.server.biometrics.AuthService;
@@ -1718,14 +1717,9 @@ public final class SystemServer implements Dumpable {
startTextToSpeechManagerService(context, t);
// System Speech Recognition Service
- if (deviceHasConfigString(context,
- R.string.config_defaultOnDeviceSpeechRecognitionService)) {
- t.traceBegin("StartSpeechRecognitionManagerService");
- mSystemServiceManager.startService(SPEECH_RECOGNITION_MANAGER_SERVICE_CLASS);
- t.traceEnd();
- } else {
- Slog.d(TAG, "System speech recognition is not defined by OEM");
- }
+ t.traceBegin("StartSpeechRecognitionManagerService");
+ mSystemServiceManager.startService(SPEECH_RECOGNITION_MANAGER_SERVICE_CLASS);
+ t.traceEnd();
// App prediction manager service
if (deviceHasConfigString(context, R.string.config_defaultAppPredictionService)) {
@@ -1785,7 +1779,7 @@ public final class SystemServer implements Dumpable {
t.traceBegin("StartIpSecService");
try {
- ipSecService = IpSecService.create(context, networkManagement);
+ ipSecService = IpSecService.create(context);
ServiceManager.addService(Context.IPSEC_SERVICE, ipSecService);
} catch (Throwable e) {
reportWtf("starting IpSec Service", e);
@@ -2150,11 +2144,9 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
t.traceEnd();
- if (AppHibernationService.isAppHibernationEnabled()) {
- t.traceBegin("StartAppHibernationService");
- mSystemServiceManager.startService(APP_HIBERNATION_SERVICE_CLASS);
- t.traceEnd();
- }
+ t.traceBegin("StartAppHibernationService");
+ mSystemServiceManager.startService(APP_HIBERNATION_SERVICE_CLASS);
+ t.traceEnd();
if (GestureLauncherService.isGestureLauncherEnabled(context.getResources())) {
t.traceBegin("StartGestureLauncher");
diff --git a/services/musicrecognition/Android.bp b/services/musicrecognition/Android.bp
index fea9efa9dde5..8298dec29884 100644
--- a/services/musicrecognition/Android.bp
+++ b/services/musicrecognition/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
filegroup {
name: "services.musicsearch-sources",
srcs: ["java/**/*.java"],
@@ -10,4 +19,4 @@ java_library_static {
defaults: ["platform_service_defaults"],
srcs: [":services.musicsearch-sources"],
libs: ["services.core", "app-compat-annotations"],
-} \ No newline at end of file
+}
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
index cbebe6984794..2219d477630e 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
@@ -38,7 +38,6 @@ import static org.testng.Assert.expectThrows;
import android.annotation.UserIdInt;
import android.app.Application;
-import android.app.backup.BackupManager.OperationType;
import android.app.backup.IBackupManagerMonitor;
import android.app.backup.IBackupObserver;
import android.app.backup.IFullBackupRestoreObserver;
@@ -874,8 +873,7 @@ public class BackupManagerServiceRoboTest {
SecurityException.class,
() ->
backupManagerService.requestBackup(
- mUserTwoId, packages, observer, monitor, 0,
- OperationType.BACKUP));
+ mUserTwoId, packages, observer, monitor, 0));
}
/**
@@ -893,11 +891,9 @@ public class BackupManagerServiceRoboTest {
IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true);
- backupManagerService.requestBackup(mUserTwoId, packages, observer, monitor, /* flags */ 0,
- OperationType.BACKUP);
+ backupManagerService.requestBackup(mUserTwoId, packages, observer, monitor, /* flags */ 0);
- verify(mUserTwoService).requestBackup(packages, observer, monitor, /* flags */ 0,
- OperationType.BACKUP);
+ verify(mUserTwoService).requestBackup(packages, observer, monitor, /* flags */ 0);
}
/** Test that the backup service routes methods correctly to the user that requests it. */
@@ -910,11 +906,9 @@ public class BackupManagerServiceRoboTest {
IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
- backupManagerService.requestBackup(mUserOneId, packages, observer, monitor, /* flags */ 0,
- OperationType.BACKUP);
+ backupManagerService.requestBackup(mUserOneId, packages, observer, monitor, /* flags */ 0);
- verify(mUserOneService).requestBackup(packages, observer, monitor, /* flags */ 0,
- OperationType.BACKUP);
+ verify(mUserOneService).requestBackup(packages, observer, monitor, /* flags */ 0);
}
/** Test that the backup service routes methods correctly to the user that requests it. */
@@ -927,11 +921,9 @@ public class BackupManagerServiceRoboTest {
IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
- backupManagerService.requestBackup(mUserTwoId, packages, observer, monitor, /* flags */ 0,
- OperationType.BACKUP);
+ backupManagerService.requestBackup(mUserTwoId, packages, observer, monitor, /* flags */ 0);
- verify(mUserOneService, never()).requestBackup(packages, observer, monitor, /* flags */ 0,
- OperationType.BACKUP);
+ verify(mUserOneService, never()).requestBackup(packages, observer, monitor, /* flags */ 0);
}
/**
@@ -1092,11 +1084,9 @@ public class BackupManagerServiceRoboTest {
registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
- backupManagerService.beginRestoreSession(mUserOneId, TEST_PACKAGE, TEST_TRANSPORT,
- OperationType.BACKUP);
+ backupManagerService.beginRestoreSession(mUserOneId, TEST_PACKAGE, TEST_TRANSPORT);
- verify(mUserOneService).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT,
- OperationType.BACKUP);
+ verify(mUserOneService).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT);
}
/** Test that the backup service does not route methods for non-registered users. */
@@ -1106,11 +1096,9 @@ public class BackupManagerServiceRoboTest {
registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
- backupManagerService.beginRestoreSession(mUserTwoId, TEST_PACKAGE, TEST_TRANSPORT,
- OperationType.BACKUP);
+ backupManagerService.beginRestoreSession(mUserTwoId, TEST_PACKAGE, TEST_TRANSPORT);
- verify(mUserOneService, never()).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT,
- OperationType.BACKUP);
+ verify(mUserOneService, never()).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT);
}
/** Test that the backup service routes methods correctly to the user that requests it. */
diff --git a/services/searchui/Android.bp b/services/searchui/Android.bp
index cc632940e4a6..3081a5111ab7 100644
--- a/services/searchui/Android.bp
+++ b/services/searchui/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
filegroup {
name: "services.searchui-sources",
srcs: ["java/**/*.java"],
diff --git a/services/smartspace/Android.bp b/services/smartspace/Android.bp
index fcf780d4d927..640a88dbaa24 100644
--- a/services/smartspace/Android.bp
+++ b/services/smartspace/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
filegroup {
name: "services.smartspace-sources",
srcs: ["java/**/*.java"],
diff --git a/services/tests/PackageManagerServiceTests/host/libs/IntentVerifyUtils/Android.bp b/services/tests/PackageManagerServiceTests/host/libs/IntentVerifyUtils/Android.bp
index b7a0624e02b8..e70a734cf271 100644
--- a/services/tests/PackageManagerServiceTests/host/libs/IntentVerifyUtils/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/libs/IntentVerifyUtils/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
java_library {
name: "PackageManagerServiceHostTestsIntentVerifyUtils",
srcs: ["src/**/*.kt"],
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
index af0ac77eaadd..7e4f0e72b62d 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test_helper_app {
name: "PackageManagerServiceDeviceSideTests",
sdk_version: "test_current",
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/Android.bp
index e82f57d20fcc..4f3f2eb1b58e 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test_helper_app {
name: "PackageManagerTestIntentVerifier",
srcs: [ "src/**/*.kt" ],
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/Android.bp
index 7161fdd33516..9f9ed24c63bc 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test_helper_app {
name: "PackageManagerTestIntentVerifierTarget1",
manifest: "AndroidManifest1.xml",
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp
index 58f17f253a24..ebad5afac625 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test_helper_app {
name: "PackageManagerTestAppDeclaresStaticLibrary",
manifest: "AndroidManifestDeclaresStaticLibrary.xml",
diff --git a/services/tests/PackageManagerServiceTests/unit/Android.bp b/services/tests/PackageManagerServiceTests/unit/Android.bp
index 4aa8abc84392..334e53a3aec7 100644
--- a/services/tests/PackageManagerServiceTests/unit/Android.bp
+++ b/services/tests/PackageManagerServiceTests/unit/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test {
name: "PackageManagerServiceUnitTests",
srcs: ["src/**/*.kt"],
diff --git a/services/tests/inprocesstests/Android.bp b/services/tests/inprocesstests/Android.bp
index 6dd059fc919d..7c237ac6befb 100644
--- a/services/tests/inprocesstests/Android.bp
+++ b/services/tests/inprocesstests/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test {
name: "FrameworksInProcessTests",
srcs: ["src/**/*.java"],
diff --git a/services/tests/mockingservicestests/jni/Android.bp b/services/tests/mockingservicestests/jni/Android.bp
index 928065a7ebd9..a32bf2c3b260 100644
--- a/services/tests/mockingservicestests/jni/Android.bp
+++ b/services/tests/mockingservicestests/jni/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
cc_library_shared {
name: "libactivitymanagermockingservicestestjni",
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
index 56d30ccdf59f..20a58426f1eb 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
@@ -139,7 +139,8 @@ public final class CachedAppOptimizerTest {
app.info.uid = packageUid;
// Exact value does not mater, it can be any state for which compaction is allowed.
app.mState.setSetProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
- app.mState.setSetAdj(905);
+ app.mState.setSetAdj(899);
+ app.mState.setCurAdj(940);
return app;
}
@@ -164,8 +165,6 @@ public final class CachedAppOptimizerTest {
CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE);
assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo(
CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE);
- assertThat(mCachedAppOptimizerUnderTest.mFullAnonRssThrottleKb).isEqualTo(
- CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB);
assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleBFGS).isEqualTo(
CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_5);
assertThat(mCachedAppOptimizerUnderTest.mCompactThrottlePersistent).isEqualTo(
@@ -176,6 +175,11 @@ public final class CachedAppOptimizerTest {
CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB);
assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
CachedAppOptimizer.DEFAULT_USE_FREEZER);
+ assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMinOomAdj).isEqualTo(
+ CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ);
+ assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMaxOomAdj).isEqualTo(
+ CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ);
+
Set<Integer> expected = new HashSet<>();
for (String s : TextUtils.split(
@@ -231,6 +235,14 @@ public final class CachedAppOptimizerTest {
Long.toString(
CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + 1), false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ CachedAppOptimizer.KEY_COMPACT_THROTTLE_MIN_OOM_ADJ,
+ Long.toString(
+ CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ + 10), false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ CachedAppOptimizer.KEY_COMPACT_THROTTLE_MAX_OOM_ADJ,
+ Long.toString(
+ CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ - 10), false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
CachedAppOptimizer.KEY_COMPACT_PROC_STATE_THROTTLE, "1,2,3", false);
assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
CachedAppOptimizer.DEFAULT_USE_FREEZER);
@@ -261,6 +273,12 @@ public final class CachedAppOptimizerTest {
CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_5 + 1);
assertThat(mCachedAppOptimizerUnderTest.mCompactThrottlePersistent).isEqualTo(
CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_6 + 1);
+ assertThat(mCachedAppOptimizerUnderTest.mFullDeltaRssThrottleKb).isEqualTo(
+ CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + 1);
+ assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMinOomAdj).isEqualTo(
+ CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ + 10);
+ assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMaxOomAdj).isEqualTo(
+ CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ - 10);
assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo(
CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f);
assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo(
@@ -437,7 +455,7 @@ public final class CachedAppOptimizerTest {
mCachedAppOptimizerUnderTest.init();
// When we override new reasonable throttle values after init...
- mCountDown = new CountDownLatch(6);
+ mCountDown = new CountDownLatch(8);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
CachedAppOptimizer.KEY_COMPACT_THROTTLE_1,
Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1 + 1), false);
@@ -456,7 +474,13 @@ public final class CachedAppOptimizerTest {
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
CachedAppOptimizer.KEY_COMPACT_THROTTLE_6,
Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_6 + 1), false);
- assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ CachedAppOptimizer.KEY_COMPACT_THROTTLE_MIN_OOM_ADJ,
+ Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ + 1), false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ CachedAppOptimizer.KEY_COMPACT_THROTTLE_MAX_OOM_ADJ,
+ Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ - 1), false);
+ assertThat(mCountDown.await(7, TimeUnit.SECONDS)).isTrue();
// Then those flags values are reflected in the compactor.
assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeSome).isEqualTo(
@@ -471,6 +495,10 @@ public final class CachedAppOptimizerTest {
CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_5 + 1);
assertThat(mCachedAppOptimizerUnderTest.mCompactThrottlePersistent).isEqualTo(
CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_6 + 1);
+ assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMinOomAdj).isEqualTo(
+ CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ + 1);
+ assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMaxOomAdj).isEqualTo(
+ CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ - 1);
}
@Test
@@ -902,7 +930,6 @@ public final class CachedAppOptimizerTest {
valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats.get(
pid).getRssAfterCompaction();
assertThat(valuesAfter).isEqualTo(rssAfter3);
-
}
@Test
@@ -954,6 +981,54 @@ public final class CachedAppOptimizerTest {
assertThat(valuesAfter).isEqualTo(rssAboveThresholdAfter);
}
+ @Test
+ public void processWithOomAdjTooSmall_notFullCompacted() throws Exception {
+ // Initialize CachedAppOptimizer and set flags to (1) enable compaction, (2) set Min and
+ // Max OOM_Adj throttles.
+ mCachedAppOptimizerUnderTest.init();
+ setFlag(CachedAppOptimizer.KEY_USE_COMPACTION, "true", true);
+ setFlag(CachedAppOptimizer.KEY_COMPACT_THROTTLE_MIN_OOM_ADJ, Long.toString(920), true);
+ setFlag(CachedAppOptimizer.KEY_COMPACT_THROTTLE_MAX_OOM_ADJ, Long.toString(950), true);
+ initActivityManagerService();
+
+ // Simulate RSS memory for which compaction should occur.
+ long[] rssBefore =
+ new long[]{/*Total RSS*/ 15000, /*File RSS*/ 15000, /*Anon RSS*/ 15000,
+ /*Swap*/ 10000};
+ long[] rssAfter =
+ new long[]{/*Total RSS*/ 8000, /*File RSS*/ 9000, /*Anon RSS*/ 6000, /*Swap*/5000};
+ // Process that passes properties.
+ int pid = 1;
+ ProcessRecord processRecord =
+ makeProcessRecord(pid, 2, 3, "p1", "app1");
+ mProcessDependencies.setRss(rssBefore);
+ mProcessDependencies.setRssAfterCompaction(rssAfter);
+
+ // Compaction should occur if (setAdj < min for process || setAdj > max for process) &&
+ // (MIN < curAdj < MAX)
+ // GIVEN OomAdj score below threshold.
+ processRecord.mState.setSetAdj(899);
+ processRecord.mState.setCurAdj(970);
+ // WHEN we try to run compaction
+ mCachedAppOptimizerUnderTest.compactAppFull(processRecord);
+ waitForHandler();
+ // THEN process IS NOT compacted.
+ assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNull();
+
+ // GIVEN (setAdj < MIN || setAdj > MAX) && (MIN < curAdj < MAX)
+ processRecord.mState.setSetAdj(910);
+ processRecord.mState.setCurAdj(930);
+ // WHEN we try to run compaction
+ mCachedAppOptimizerUnderTest.compactAppFull(processRecord);
+ waitForHandler();
+ // THEN process IS compacted.
+ assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();
+ long[] valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats
+ .get(pid)
+ .getRssAfterCompaction();
+ assertThat(valuesAfter).isEqualTo(rssAfter);
+ }
+
private void setFlag(String key, String value, boolean defaultValue) throws Exception {
mCountDown = new CountDownLatch(1);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index a382e85538cd..1c45203bb3c9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -46,6 +46,7 @@ import static com.android.server.am.ProcessList.HEAVY_WEIGHT_APP_ADJ;
import static com.android.server.am.ProcessList.HOME_APP_ADJ;
import static com.android.server.am.ProcessList.PERCEPTIBLE_APP_ADJ;
import static com.android.server.am.ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
+import static com.android.server.am.ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ;
import static com.android.server.am.ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
import static com.android.server.am.ProcessList.PERSISTENT_PROC_ADJ;
import static com.android.server.am.ProcessList.PERSISTENT_SERVICE_ADJ;
@@ -877,6 +878,39 @@ public class MockingOomAdjusterTests {
@SuppressWarnings("GuardedBy")
@Test
+ public void testUpdateOomAdj_DoOne_Service_MediumPerceptible() {
+ {
+ ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+ MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+ ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+ MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+ bindService(app, client, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
+ client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+ assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ, app.mState.getSetAdj());
+ }
+
+ {
+ ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+ MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+ ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+ MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+ WindowProcessController wpc = client.getWindowProcessController();
+ doReturn(true).when(wpc).isHeavyWeightProcess();
+ bindService(app, client, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
+ client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+ doReturn(false).when(wpc).isHeavyWeightProcess();
+
+ assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ, app.mState.getSetAdj());
+ }
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
public void testUpdateOomAdj_DoOne_Service_Other() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 7f8784dc2599..728b97cc3968 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -25,8 +25,10 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
@@ -94,11 +96,13 @@ public class LocalDisplayAdapterTest {
private Injector mInjector;
+ @Mock
+ private LocalDisplayAdapter.SurfaceControlProxy mSurfaceControlProxy;
+
@Before
public void setUp() throws Exception {
mMockitoSession = mockitoSession()
.initMocks(this)
- .mockStatic(SurfaceControl.class)
.strictness(Strictness.LENIENT)
.startMocking();
mHandler = new Handler(Looper.getMainLooper());
@@ -227,6 +231,7 @@ public class LocalDisplayAdapterTest {
setUpDisplay(display);
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+ assertTrue(mListener.traversalRequested);
assertThat(mListener.changedDisplays.size()).isGreaterThan(0);
// Verify the supported modes are updated accordingly.
@@ -333,6 +338,7 @@ public class LocalDisplayAdapterTest {
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+ assertTrue(mListener.traversalRequested);
assertThat(mListener.addedDisplays.size()).isEqualTo(1);
assertThat(mListener.changedDisplays.size()).isEqualTo(1);
@@ -380,6 +386,7 @@ public class LocalDisplayAdapterTest {
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+ assertTrue(mListener.traversalRequested);
assertThat(mListener.addedDisplays.size()).isEqualTo(1);
assertThat(mListener.changedDisplays.size()).isEqualTo(1);
@@ -418,6 +425,7 @@ public class LocalDisplayAdapterTest {
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+ assertTrue(mListener.traversalRequested);
assertThat(mListener.addedDisplays.size()).isEqualTo(1);
assertThat(mListener.changedDisplays.size()).isEqualTo(1);
@@ -429,6 +437,74 @@ public class LocalDisplayAdapterTest {
}
@Test
+ public void testAfterDisplayChange_AllmSupportIsUpdated() throws Exception {
+ FakeDisplay display = new FakeDisplay(PORT_A);
+ display.dynamicInfo.autoLowLatencyModeSupported = true;
+ setUpDisplay(display);
+ updateAvailableDisplays();
+ mAdapter.registerLocked();
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+ assertThat(mListener.addedDisplays.size()).isEqualTo(1);
+ assertThat(mListener.changedDisplays).isEmpty();
+
+ DisplayDeviceInfo displayDeviceInfo = mListener.addedDisplays.get(0)
+ .getDisplayDeviceInfoLocked();
+
+ assertThat(displayDeviceInfo.allmSupported).isTrue();
+
+ // Change the display
+ display.dynamicInfo.autoLowLatencyModeSupported = false;
+ setUpDisplay(display);
+ mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+ assertTrue(mListener.traversalRequested);
+ assertThat(mListener.addedDisplays.size()).isEqualTo(1);
+ assertThat(mListener.changedDisplays.size()).isEqualTo(1);
+
+ DisplayDevice displayDevice = mListener.changedDisplays.get(0);
+ displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
+ displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked();
+
+ assertThat(displayDeviceInfo.allmSupported).isFalse();
+ }
+
+ @Test
+ public void testAfterDisplayChange_GameContentTypeSupportIsUpdated() throws Exception {
+ FakeDisplay display = new FakeDisplay(PORT_A);
+ display.dynamicInfo.gameContentTypeSupported = true;
+ setUpDisplay(display);
+ updateAvailableDisplays();
+ mAdapter.registerLocked();
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+ assertThat(mListener.addedDisplays.size()).isEqualTo(1);
+ assertThat(mListener.changedDisplays).isEmpty();
+
+ DisplayDeviceInfo displayDeviceInfo = mListener.addedDisplays.get(0)
+ .getDisplayDeviceInfoLocked();
+
+ assertThat(displayDeviceInfo.gameContentTypeSupported).isTrue();
+
+ // Change the display
+ display.dynamicInfo.gameContentTypeSupported = false;
+ setUpDisplay(display);
+ mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+ assertTrue(mListener.traversalRequested);
+ assertThat(mListener.addedDisplays.size()).isEqualTo(1);
+ assertThat(mListener.changedDisplays.size()).isEqualTo(1);
+
+ DisplayDevice displayDevice = mListener.changedDisplays.get(0);
+ displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
+ displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked();
+
+ assertThat(displayDeviceInfo.gameContentTypeSupported).isFalse();
+ }
+
+ @Test
public void testAfterDisplayChange_ColorModesAreUpdated() throws Exception {
FakeDisplay display = new FakeDisplay(PORT_A);
final int[] initialColorModes = new int[]{Display.COLOR_MODE_BT709};
@@ -454,6 +530,7 @@ public class LocalDisplayAdapterTest {
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+ assertTrue(mListener.traversalRequested);
assertThat(mListener.addedDisplays.size()).isEqualTo(1);
assertThat(mListener.changedDisplays.size()).isEqualTo(1);
@@ -480,6 +557,30 @@ public class LocalDisplayAdapterTest {
mAdapter.registerLocked();
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+ assertThat(mListener.addedDisplays.size()).isEqualTo(1);
+ DisplayDevice displayDevice = mListener.addedDisplays.get(0);
+
+ int baseModeId = Arrays.stream(displayDevice.getDisplayDeviceInfoLocked().supportedModes)
+ .filter(mode -> mode.getRefreshRate() == 60f)
+ .findFirst()
+ .get()
+ .getModeId();
+
+ displayDevice.setDesiredDisplayModeSpecsLocked(
+ new DisplayModeDirector.DesiredDisplayModeSpecs(
+ /*baseModeId*/ baseModeId,
+ /*allowGroupSwitching*/ false,
+ new DisplayModeDirector.RefreshRateRange(60f, 60f),
+ new DisplayModeDirector.RefreshRateRange(60f, 60f)
+ ));
+ verify(mSurfaceControlProxy).setDesiredDisplayModeSpecs(display.token,
+ new SurfaceControl.DesiredDisplayModeSpecs(
+ /* baseModeId */ 0,
+ /* allowGroupSwitching */ false,
+ /* primaryRange */ 60f, 60f,
+ /* appRange */ 60f, 60f
+ ));
+
// Change the display
display.dynamicInfo.supportedDisplayModes = new SurfaceControl.DisplayMode[]{
createFakeDisplayMode(2, 1920, 1080, 60f)
@@ -489,36 +590,64 @@ public class LocalDisplayAdapterTest {
display.desiredDisplayModeSpecs.defaultMode = 1;
setUpDisplay(display);
- updateAvailableDisplays();
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+ assertTrue(mListener.traversalRequested);
+
+ displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
+
+ baseModeId = displayDevice.getDisplayDeviceInfoLocked().supportedModes[0].getModeId();
+
+ // The traversal request will call setDesiredDisplayModeSpecsLocked on the display device
+ displayDevice.setDesiredDisplayModeSpecsLocked(
+ new DisplayModeDirector.DesiredDisplayModeSpecs(
+ /*baseModeId*/ baseModeId,
+ /*allowGroupSwitching*/ false,
+ new DisplayModeDirector.RefreshRateRange(60f, 60f),
+ new DisplayModeDirector.RefreshRateRange(60f, 60f)
+ ));
+
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+ // Verify that this will reapply the desired modes.
+ verify(mSurfaceControlProxy).setDesiredDisplayModeSpecs(display.token,
+ new SurfaceControl.DesiredDisplayModeSpecs(
+ /* baseModeId */ 2,
+ /* allowGroupSwitching */ false,
+ /* primaryRange */ 60f, 60f,
+ /* appRange */ 60f, 60f
+ ));
}
@Test
public void testBacklightAdapter_withSurfaceControlSupport() {
final Binder displayToken = new Binder();
- doReturn(true).when(() -> SurfaceControl.getDisplayBrightnessSupport(displayToken));
+
+ when(mSurfaceControlProxy.getDisplayBrightnessSupport(displayToken)).thenReturn(true);
// Test as default display
- BacklightAdapter ba = new BacklightAdapter(displayToken, true /*isDefault*/);
+ BacklightAdapter ba = new BacklightAdapter(displayToken, true /*isDefault*/,
+ mSurfaceControlProxy);
ba.setBrightness(0.514f);
- verify(() -> SurfaceControl.setDisplayBrightness(displayToken, 0.514f));
+ verify(mSurfaceControlProxy).setDisplayBrightness(displayToken, 0.514f);
// Test as not default display
- BacklightAdapter ba2 = new BacklightAdapter(displayToken,
- false /*isDefault*/);
+ BacklightAdapter ba2 = new BacklightAdapter(displayToken, false /*isDefault*/,
+ mSurfaceControlProxy);
ba2.setBrightness(0.323f);
- verify(() -> SurfaceControl.setDisplayBrightness(displayToken, 0.323f));
+ verify(mSurfaceControlProxy).setDisplayBrightness(displayToken, 0.323f);
}
@Test
public void testBacklightAdapter_withoutSourceControlSupport_defaultDisplay() {
final Binder displayToken = new Binder();
- doReturn(false).when(() -> SurfaceControl.getDisplayBrightnessSupport(displayToken));
+ when(mSurfaceControlProxy.getDisplayBrightnessSupport(displayToken)).thenReturn(false);
doReturn(mMockedBacklight).when(mMockedLightsManager)
.getLight(LightsManager.LIGHT_ID_BACKLIGHT);
- BacklightAdapter ba = new BacklightAdapter(displayToken, true /*isDefault*/);
+ BacklightAdapter ba = new BacklightAdapter(displayToken, true /*isDefault*/,
+ mSurfaceControlProxy);
ba.setBrightness(0.123f);
verify(mMockedBacklight).setBrightness(0.123f);
}
@@ -526,11 +655,12 @@ public class LocalDisplayAdapterTest {
@Test
public void testBacklightAdapter_withoutSourceControlSupport_nonDefaultDisplay() {
final Binder displayToken = new Binder();
- doReturn(false).when(() -> SurfaceControl.getDisplayBrightnessSupport(displayToken));
+ when(mSurfaceControlProxy.getDisplayBrightnessSupport(displayToken)).thenReturn(false);
doReturn(mMockedBacklight).when(mMockedLightsManager)
.getLight(LightsManager.LIGHT_ID_BACKLIGHT);
- BacklightAdapter ba = new BacklightAdapter(displayToken, false /*isDefault*/);
+ BacklightAdapter ba = new BacklightAdapter(displayToken, false /*isDefault*/,
+ mSurfaceControlProxy);
ba.setBrightness(0.456f);
// Adapter does not forward any brightness in this case.
@@ -618,13 +748,14 @@ public class LocalDisplayAdapterTest {
private void setUpDisplay(FakeDisplay display) {
mAddresses.add(display.address);
- doReturn(display.token).when(() ->
- SurfaceControl.getPhysicalDisplayToken(display.address.getPhysicalDisplayId()));
- doReturn(display.info).when(() -> SurfaceControl.getStaticDisplayInfo(display.token));
- doReturn(display.dynamicInfo).when(
- () -> SurfaceControl.getDynamicDisplayInfo(display.token));
- doReturn(display.desiredDisplayModeSpecs)
- .when(() -> SurfaceControl.getDesiredDisplayModeSpecs(display.token));
+ when(mSurfaceControlProxy.getPhysicalDisplayToken(display.address.getPhysicalDisplayId()))
+ .thenReturn(display.token);
+ when(mSurfaceControlProxy.getStaticDisplayInfo(display.token))
+ .thenReturn(display.info);
+ when(mSurfaceControlProxy.getDynamicDisplayInfo(display.token))
+ .thenReturn(display.dynamicInfo);
+ when(mSurfaceControlProxy.getDesiredDisplayModeSpecs(display.token))
+ .thenReturn(display.desiredDisplayModeSpecs);
}
private void updateAvailableDisplays() {
@@ -634,7 +765,7 @@ public class LocalDisplayAdapterTest {
ids[i] = address.getPhysicalDisplayId();
i++;
}
- doReturn(ids).when(() -> SurfaceControl.getPhysicalDisplayIds());
+ when(mSurfaceControlProxy.getPhysicalDisplayIds()).thenReturn(ids);
}
private static DisplayAddress.Physical createDisplayAddress(int port) {
@@ -649,7 +780,7 @@ public class LocalDisplayAdapterTest {
private static SurfaceControl.DisplayMode createFakeDisplayMode(int id, int width, int height,
float refreshRate) {
- return createFakeDisplayMode(id, width, height, refreshRate, 0);
+ return createFakeDisplayMode(id, width, height, refreshRate, /* group */ 0);
}
private static SurfaceControl.DisplayMode createFakeDisplayMode(int id, int width, int height,
@@ -702,14 +833,21 @@ public class LocalDisplayAdapterTest {
LocalDisplayAdapter.DisplayEventListener listener) {
mTransmitter = new HotplugTransmitter(looper, listener);
}
+
public HotplugTransmitter getTransmitter() {
return mTransmitter;
}
+
+ @Override
+ public LocalDisplayAdapter.SurfaceControlProxy getSurfaceControlProxy() {
+ return mSurfaceControlProxy;
+ }
}
private class TestListener implements DisplayAdapter.Listener {
public ArrayList<DisplayDevice> addedDisplays = new ArrayList<>();
public ArrayList<DisplayDevice> changedDisplays = new ArrayList<>();
+ public boolean traversalRequested = false;
@Override
public void onDisplayDeviceEvent(DisplayDevice device, int event) {
@@ -722,6 +860,8 @@ public class LocalDisplayAdapterTest {
@Override
public void onTraversalRequested() {
+ traversalRequested = true;
}
}
+
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 88a691bbc209..bf95f4c51d96 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -31,6 +31,7 @@ import static com.android.server.job.JobSchedulerService.RARE_INDEX;
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.WORKING_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+import static com.android.server.job.JobSchedulerService.sSystemClock;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -58,6 +59,7 @@ import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.IUidObserver;
import android.app.job.JobInfo;
+import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
@@ -85,6 +87,7 @@ import com.android.server.job.JobSchedulerService;
import com.android.server.job.JobStore;
import com.android.server.job.controllers.QuotaController.ExecutionStats;
import com.android.server.job.controllers.QuotaController.QcConstants;
+import com.android.server.job.controllers.QuotaController.ShrinkableDebits;
import com.android.server.job.controllers.QuotaController.TimingSession;
import com.android.server.usage.AppStandbyInternal;
@@ -125,6 +128,7 @@ public class QuotaControllerTest {
private int mSourceUid;
private PowerAllowlistInternal.TempAllowlistChangeListener mTempAllowlistListener;
private IUidObserver mUidObserver;
+ private UsageStatsManagerInternal.UsageEventListener mUsageEventListener;
DeviceConfig.Properties.Builder mDeviceConfigPropertiesBuilder;
private MockitoSession mMockingSession;
@@ -218,6 +222,8 @@ public class QuotaControllerTest {
ArgumentCaptor.forClass(IUidObserver.class);
ArgumentCaptor<PowerAllowlistInternal.TempAllowlistChangeListener> taChangeCaptor =
ArgumentCaptor.forClass(PowerAllowlistInternal.TempAllowlistChangeListener.class);
+ ArgumentCaptor<UsageStatsManagerInternal.UsageEventListener> ueListenerCaptor =
+ ArgumentCaptor.forClass(UsageStatsManagerInternal.UsageEventListener.class);
mQuotaController = new QuotaController(mJobSchedulerService,
mock(BackgroundJobsController.class), mock(ConnectivityController.class));
@@ -229,6 +235,8 @@ public class QuotaControllerTest {
verify(mPowerAllowlistInternal)
.registerTempAllowlistChangeListener(taChangeCaptor.capture());
mTempAllowlistListener = taChangeCaptor.getValue();
+ verify(mUsageStatsManager).registerListener(ueListenerCaptor.capture());
+ mUsageEventListener = ueListenerCaptor.getValue();
try {
verify(activityManager).registerUidObserver(
uidObserverCaptor.capture(),
@@ -288,7 +296,7 @@ public class QuotaControllerTest {
verify(foregroundUids, timeout(2 * SECOND_IN_MILLIS).times(1)).delete(eq(uid));
assertFalse(foregroundUids.get(uid));
}
- waitForQuietBackground();
+ waitForNonDelayedMessagesProcessed();
} catch (Exception e) {
fail("exception encountered: " + e.getMessage());
}
@@ -385,13 +393,8 @@ public class QuotaControllerTest {
}
}
- private void waitForQuietBackground() throws Exception {
- for (int i = 0; i < 5; ++i) {
- if (!mQuotaController.isActiveBackgroundProcessing()) {
- break;
- }
- Thread.sleep(500);
- }
+ private void waitForNonDelayedMessagesProcessed() {
+ mQuotaController.getHandler().runWithScissors(() -> {}, 15_000);
}
@Test
@@ -1330,7 +1333,9 @@ public class QuotaControllerTest {
timeUsedMs, 5), true);
JobStatus job = createExpeditedJobStatus("testGetMaxJobExecutionTimeLocked_EJ", 0);
setStandbyBucket(RARE_INDEX, job);
- mQuotaController.maybeStartTrackingJobLocked(job, null);
+ synchronized (mQuotaController.mLock) {
+ mQuotaController.maybeStartTrackingJobLocked(job, null);
+ }
setCharging();
synchronized (mQuotaController.mLock) {
@@ -5158,4 +5163,257 @@ public class QuotaControllerTest {
eq(10 * SECOND_IN_MILLIS));
verify(handler, never()).sendMessageDelayed(any(), eq(remainingTimeMs));
}
+
+ @Test
+ public void testEJDebitTallying() {
+ setStandbyBucket(RARE_INDEX);
+ setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+ setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 10 * MINUTE_IN_MILLIS);
+ // 15 seconds for each 30 second chunk.
+ setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, 30 * SECOND_IN_MILLIS);
+ setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 15 * SECOND_IN_MILLIS);
+
+ // No history. Debits should be 0.
+ ShrinkableDebits debit = mQuotaController.getEJDebitsLocked(SOURCE_USER_ID, SOURCE_PACKAGE);
+ assertEquals(0, debit.getTallyLocked());
+ assertEquals(10 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ // Regular job shouldn't affect EJ tally.
+ JobStatus regJob = createJobStatus("testEJDebitTallying", 1);
+ synchronized (mQuotaController.mLock) {
+ mQuotaController.maybeStartTrackingJobLocked(regJob, null);
+ mQuotaController.prepareForExecutionLocked(regJob);
+ }
+ advanceElapsedClock(5000);
+ synchronized (mQuotaController.mLock) {
+ mQuotaController.maybeStopTrackingJobLocked(regJob, null, false);
+ }
+ assertEquals(0, debit.getTallyLocked());
+ assertEquals(10 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ // EJ job should affect EJ tally.
+ JobStatus eJob = createExpeditedJobStatus("testEJDebitTallying", 2);
+ synchronized (mQuotaController.mLock) {
+ mQuotaController.maybeStartTrackingJobLocked(eJob, null);
+ mQuotaController.prepareForExecutionLocked(eJob);
+ }
+ advanceElapsedClock(5 * MINUTE_IN_MILLIS);
+ synchronized (mQuotaController.mLock) {
+ mQuotaController.maybeStopTrackingJobLocked(eJob, null, false);
+ }
+ assertEquals(5 * MINUTE_IN_MILLIS, debit.getTallyLocked());
+ assertEquals(5 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ // Instantaneous event for a different user shouldn't affect tally.
+ advanceElapsedClock(5 * MINUTE_IN_MILLIS);
+ setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_INTERACTION_MS, MINUTE_IN_MILLIS);
+
+ UsageEvents.Event event =
+ new UsageEvents.Event(UsageEvents.Event.USER_INTERACTION, sSystemClock.millis());
+ event.mPackage = SOURCE_PACKAGE;
+ mUsageEventListener.onUsageEvent(SOURCE_USER_ID + 10, event);
+ assertEquals(5 * MINUTE_IN_MILLIS, debit.getTallyLocked());
+
+ // Instantaneous event for correct user should reduce tally.
+ advanceElapsedClock(5 * MINUTE_IN_MILLIS);
+
+ mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+ waitForNonDelayedMessagesProcessed();
+ assertEquals(4 * MINUTE_IN_MILLIS, debit.getTallyLocked());
+ assertEquals(6 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ // Activity start shouldn't reduce tally, but duration with activity started should affect
+ // remaining EJ time.
+ advanceElapsedClock(5 * MINUTE_IN_MILLIS);
+ event = new UsageEvents.Event(UsageEvents.Event.ACTIVITY_RESUMED, sSystemClock.millis());
+ event.mPackage = SOURCE_PACKAGE;
+ mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+ waitForNonDelayedMessagesProcessed();
+ advanceElapsedClock(30 * SECOND_IN_MILLIS);
+ assertEquals(4 * MINUTE_IN_MILLIS, debit.getTallyLocked());
+ assertEquals(6 * MINUTE_IN_MILLIS + 15 * SECOND_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ advanceElapsedClock(30 * SECOND_IN_MILLIS);
+ assertEquals(4 * MINUTE_IN_MILLIS, debit.getTallyLocked());
+ assertEquals(6 * MINUTE_IN_MILLIS + 30 * SECOND_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ // With activity pausing/stopping/destroying, tally should be updated.
+ advanceElapsedClock(MINUTE_IN_MILLIS);
+ event = new UsageEvents.Event(UsageEvents.Event.ACTIVITY_DESTROYED, sSystemClock.millis());
+ event.mPackage = SOURCE_PACKAGE;
+ mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+ waitForNonDelayedMessagesProcessed();
+ assertEquals(3 * MINUTE_IN_MILLIS, debit.getTallyLocked());
+ assertEquals(7 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ }
+
+ @Test
+ public void testEJDebitTallying_StaleSession() {
+ setStandbyBucket(RARE_INDEX);
+ setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 10 * MINUTE_IN_MILLIS);
+
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ TimingSession ts = new TimingSession(nowElapsed, nowElapsed + 10 * MINUTE_IN_MILLIS, 5);
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, ts, true);
+
+ // Make the session stale.
+ advanceElapsedClock(12 * MINUTE_IN_MILLIS + mQcConstants.EJ_WINDOW_SIZE_MS);
+
+ // With lazy deletion, we don't update the tally until getRemainingEJExecutionTimeLocked()
+ // is called, so call that first.
+ assertEquals(10 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ ShrinkableDebits debit = mQuotaController.getEJDebitsLocked(SOURCE_USER_ID, SOURCE_PACKAGE);
+ assertEquals(0, debit.getTallyLocked());
+ }
+
+ /**
+ * Tests that rewards are properly accounted when there's no EJ running and the rewards exceed
+ * the accumulated debits.
+ */
+ @Test
+ public void testEJDebitTallying_RewardExceedDebits_NoActiveSession() {
+ setStandbyBucket(WORKING_INDEX);
+ setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+ setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_WORKING_MS, 30 * MINUTE_IN_MILLIS);
+ setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_INTERACTION_MS, MINUTE_IN_MILLIS);
+
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ TimingSession ts = new TimingSession(nowElapsed - 5 * MINUTE_IN_MILLIS,
+ nowElapsed - 4 * MINUTE_IN_MILLIS, 2);
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, ts, true);
+
+ ShrinkableDebits debit = mQuotaController.getEJDebitsLocked(SOURCE_USER_ID, SOURCE_PACKAGE);
+ assertEquals(MINUTE_IN_MILLIS, debit.getTallyLocked());
+ assertEquals(29 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ advanceElapsedClock(30 * SECOND_IN_MILLIS);
+ UsageEvents.Event event =
+ new UsageEvents.Event(UsageEvents.Event.USER_INTERACTION, sSystemClock.millis());
+ event.mPackage = SOURCE_PACKAGE;
+ mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+ waitForNonDelayedMessagesProcessed();
+ assertEquals(0, debit.getTallyLocked());
+ assertEquals(30 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ advanceElapsedClock(MINUTE_IN_MILLIS);
+ assertEquals(0, debit.getTallyLocked());
+ assertEquals(30 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ // Excessive rewards don't increase maximum quota.
+ event = new UsageEvents.Event(UsageEvents.Event.USER_INTERACTION, sSystemClock.millis());
+ event.mPackage = SOURCE_PACKAGE;
+ mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+ waitForNonDelayedMessagesProcessed();
+ assertEquals(0, debit.getTallyLocked());
+ assertEquals(30 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ }
+
+ /**
+ * Tests that rewards are properly accounted when there's an active EJ running and the rewards
+ * exceed the accumulated debits.
+ */
+ @Test
+ public void testEJDebitTallying_RewardExceedDebits_ActiveSession() {
+ setStandbyBucket(WORKING_INDEX);
+ setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+ setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_WORKING_MS, 30 * MINUTE_IN_MILLIS);
+ setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_INTERACTION_MS, MINUTE_IN_MILLIS);
+ // 15 seconds for each 30 second chunk.
+ setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, 30 * SECOND_IN_MILLIS);
+ setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 15 * SECOND_IN_MILLIS);
+
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ TimingSession ts = new TimingSession(nowElapsed - 5 * MINUTE_IN_MILLIS,
+ nowElapsed - 4 * MINUTE_IN_MILLIS, 2);
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, ts, true);
+
+ ShrinkableDebits debit = mQuotaController.getEJDebitsLocked(SOURCE_USER_ID, SOURCE_PACKAGE);
+ assertEquals(MINUTE_IN_MILLIS, debit.getTallyLocked());
+ assertEquals(29 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ // With rewards coming in while an EJ is running, the remaining execution time should be
+ // adjusted accordingly (decrease due to EJ running + increase from reward).
+ JobStatus eJob =
+ createExpeditedJobStatus("testEJDebitTallying_RewardExceedDebits_ActiveSession", 1);
+ synchronized (mQuotaController.mLock) {
+ mQuotaController.maybeStartTrackingJobLocked(eJob, null);
+ mQuotaController.prepareForExecutionLocked(eJob);
+ }
+ advanceElapsedClock(30 * SECOND_IN_MILLIS);
+ assertEquals(MINUTE_IN_MILLIS, debit.getTallyLocked());
+ assertEquals(28 * MINUTE_IN_MILLIS + 30 * SECOND_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ advanceElapsedClock(30 * SECOND_IN_MILLIS);
+ UsageEvents.Event event =
+ new UsageEvents.Event(UsageEvents.Event.USER_INTERACTION, sSystemClock.millis());
+ event.mPackage = SOURCE_PACKAGE;
+ mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+ waitForNonDelayedMessagesProcessed();
+ assertEquals(0, debit.getTallyLocked());
+ assertEquals(29 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ advanceElapsedClock(MINUTE_IN_MILLIS);
+ assertEquals(0, debit.getTallyLocked());
+ assertEquals(28 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ // Activity start shouldn't reduce tally, but duration with activity started should affect
+ // remaining EJ time.
+ event = new UsageEvents.Event(UsageEvents.Event.ACTIVITY_RESUMED, sSystemClock.millis());
+ event.mPackage = SOURCE_PACKAGE;
+ mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+ waitForNonDelayedMessagesProcessed();
+ advanceElapsedClock(30 * SECOND_IN_MILLIS);
+ assertEquals(0, debit.getTallyLocked());
+ // Decrease by 30 seconds for running EJ, increase by 15 seconds due to ongoing activity.
+ assertEquals(27 * MINUTE_IN_MILLIS + 45 * SECOND_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ advanceElapsedClock(30 * SECOND_IN_MILLIS);
+ assertEquals(0, debit.getTallyLocked());
+ assertEquals(27 * MINUTE_IN_MILLIS + 30 * SECOND_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ advanceElapsedClock(MINUTE_IN_MILLIS);
+ assertEquals(0, debit.getTallyLocked());
+ assertEquals(27 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ event = new UsageEvents.Event(UsageEvents.Event.USER_INTERACTION, sSystemClock.millis());
+ event.mPackage = SOURCE_PACKAGE;
+ mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+ waitForNonDelayedMessagesProcessed();
+ assertEquals(0, debit.getTallyLocked());
+ assertEquals(28 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ advanceElapsedClock(MINUTE_IN_MILLIS);
+ assertEquals(0, debit.getTallyLocked());
+ assertEquals(27 * MINUTE_IN_MILLIS + 30 * SECOND_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ // At this point, with activity pausing/stopping/destroying, since we're giving a reward,
+ // tally should remain 0, and time remaining shouldn't change since it was accounted for
+ // at every step.
+ event = new UsageEvents.Event(UsageEvents.Event.ACTIVITY_DESTROYED, sSystemClock.millis());
+ event.mPackage = SOURCE_PACKAGE;
+ mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+ waitForNonDelayedMessagesProcessed();
+ assertEquals(0, debit.getTallyLocked());
+ assertEquals(27 * MINUTE_IN_MILLIS + 30 * SECOND_IN_MILLIS,
+ mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index 66b037d70a40..68d6557880c4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -123,9 +123,10 @@ public class LocationProviderManagerTest {
.setPowerUsage(POWER_USAGE_HIGH)
.setAccuracy(ProviderProperties.ACCURACY_FINE)
.build();
+ private static final CallerIdentity PROVIDER_IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1,
+ "mypackage", "attribution");
private static final CallerIdentity IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1,
- "mypackage",
- "attribution");
+ "mypackage", "attribution", "listener");
private static final WorkSource WORK_SOURCE = new WorkSource(IDENTITY.getUid());
private Random mRandom;
@@ -169,7 +170,7 @@ public class LocationProviderManagerTest {
mPassive.startManager();
mPassive.setRealProvider(new PassiveLocationProvider(mContext));
- mProvider = new TestProvider(PROPERTIES, IDENTITY);
+ mProvider = new TestProvider(PROPERTIES, PROVIDER_IDENTITY);
mProvider.setProviderAllowed(true);
mManager = new LocationProviderManager(mContext, mInjector, eventLog, NAME, mPassive);
@@ -351,7 +352,7 @@ public class LocationProviderManagerTest {
@Test
public void testGetLastLocation_ClearOnMockRemoval() {
- MockLocationProvider mockProvider = new MockLocationProvider(PROPERTIES, IDENTITY);
+ MockLocationProvider mockProvider = new MockLocationProvider(PROPERTIES, PROVIDER_IDENTITY);
mockProvider.setAllowed(true);
mManager.setMockProvider(mockProvider);
@@ -441,7 +442,7 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_SameProcess() throws Exception {
CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
- "attribution");
+ "attribution", "listener");
ILocationListener listener = createMockLocationListener();
mManager.registerLocationRequest(
@@ -477,7 +478,7 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_Unregister_SameProcess() throws Exception {
CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
- "attribution");
+ "attribution", "listener");
ILocationListener listener = createMockLocationListener();
mManager.registerLocationRequest(
@@ -604,7 +605,7 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_Wakelock() throws Exception {
CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
- "attribution");
+ "attribution", "listener");
ILocationListener listener = createMockLocationListener();
mManager.registerLocationRequest(
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
index 1328b91d03f9..07f67327b2bf 100644
--- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
@@ -110,6 +110,8 @@ public final class AppHibernationServiceTest {
UserInfo userInfo = addUser(USER_ID_1);
mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_1);
+
+ mAppHibernationService.mIsServiceEnabled = true;
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
index 73b0105210c4..6890ed1688bb 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
@@ -28,6 +28,7 @@ import android.app.appsearch.SearchSpec;
import android.app.appsearch.SetSchemaResponse;
import android.app.appsearch.exceptions.AppSearchException;
import android.content.Context;
+import android.util.ArrayMap;
import android.util.ArraySet;
import androidx.test.core.app.ApplicationProvider;
@@ -55,6 +56,7 @@ import org.junit.rules.TemporaryFolder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Set;
public class AppSearchImplTest {
@@ -971,21 +973,46 @@ public class AppSearchImplTest {
}
@Test
- public void testHasSchemaType() throws Exception {
- // Nothing exists yet
- assertThat(mAppSearchImpl.hasSchemaTypeLocked("package", "database", "Schema")).isFalse();
+ public void testGetPackageToDatabases() throws Exception {
+ Map<String, Set<String>> existingMapping = mAppSearchImpl.getPackageToDatabases();
+ Map<String, Set<String>> expectedMapping = new ArrayMap<>();
+ expectedMapping.putAll(existingMapping);
+ // Has database1
+ expectedMapping.put("package1", ImmutableSet.of("database1"));
mAppSearchImpl.setSchema(
- "package",
- "database",
- Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
+ "package1",
+ "database1",
+ Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false);
- assertThat(mAppSearchImpl.hasSchemaTypeLocked("package", "database", "Schema")).isTrue();
+ assertThat(mAppSearchImpl.getPackageToDatabases())
+ .containsExactlyEntriesIn(expectedMapping);
- assertThat(mAppSearchImpl.hasSchemaTypeLocked("package", "database", "UnknownSchema"))
- .isFalse();
+ // Has both databases
+ expectedMapping.put("package1", ImmutableSet.of("database1", "database2"));
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database2",
+ Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false);
+ assertThat(mAppSearchImpl.getPackageToDatabases())
+ .containsExactlyEntriesIn(expectedMapping);
+
+ // Has both packages
+ expectedMapping.put("package2", ImmutableSet.of("database1"));
+ mAppSearchImpl.setSchema(
+ "package2",
+ "database1",
+ Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false);
+ assertThat(mAppSearchImpl.getPackageToDatabases())
+ .containsExactlyEntriesIn(expectedMapping);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
new file mode 100644
index 000000000000..4308885faaad
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appsearch.external.localstorage.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+public class AppSearchStatsTest {
+ static final String TEST_PACKAGE_NAME = "com.google.test";
+ static final String TEST_DATA_BASE = "testDataBase";
+ static final int TEST_STATUS_CODE = 2;
+ static final int TEST_TOTAL_LATENCY_MILLIS = 20;
+
+ @Test
+ public void testAppSearchStats_GeneralStats() {
+ final GeneralStats gStats =
+ new GeneralStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE)
+ .setStatusCode(TEST_STATUS_CODE)
+ .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
+ .build();
+
+ assertThat(gStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ assertThat(gStats.getDatabase()).isEqualTo(TEST_DATA_BASE);
+ assertThat(gStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE);
+ assertThat(gStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS);
+ }
+
+ @Test
+ public void testAppSearchStats_CallStats() {
+ final int estimatedBinderLatencyMillis = 1;
+ final int numOperationsSucceeded = 2;
+ final int numOperationsFailed = 3;
+
+ final GeneralStats gStats =
+ new GeneralStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE)
+ .setStatusCode(TEST_STATUS_CODE)
+ .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
+ .build();
+ final @CallStats.CallType int callType = CallStats.CALL_TYPE_PUT_DOCUMENTS;
+ final CallStats cStats =
+ new CallStats.Builder(gStats)
+ .setCallType(callType)
+ .setEstimatedBinderLatencyMillis(estimatedBinderLatencyMillis)
+ .setNumOperationsSucceeded(numOperationsSucceeded)
+ .setNumOperationsFailed(numOperationsFailed)
+ .build();
+
+ assertThat(cStats.getGeneralStats().getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ assertThat(cStats.getGeneralStats().getDatabase()).isEqualTo(TEST_DATA_BASE);
+ assertThat(cStats.getGeneralStats().getStatusCode()).isEqualTo(TEST_STATUS_CODE);
+ assertThat(cStats.getGeneralStats().getTotalLatencyMillis())
+ .isEqualTo(TEST_TOTAL_LATENCY_MILLIS);
+ assertThat(cStats.getEstimatedBinderLatencyMillis())
+ .isEqualTo(estimatedBinderLatencyMillis);
+ assertThat(cStats.getCallType()).isEqualTo(callType);
+ assertThat(cStats.getNumOperationsSucceeded()).isEqualTo(numOperationsSucceeded);
+ assertThat(cStats.getNumOperationsFailed()).isEqualTo(numOperationsFailed);
+ }
+
+ @Test
+ public void testAppSearchStats_PutDocumentStats() {
+ final int generateDocumentProtoLatencyMillis = 1;
+ final int rewriteDocumentTypesLatencyMillis = 2;
+ final int nativeLatencyMillis = 3;
+ final int nativeDocumentStoreLatencyMillis = 4;
+ final int nativeIndexLatencyMillis = 5;
+ final int nativeIndexMergeLatencyMillis = 6;
+ final int nativeDocumentSize = 7;
+ final int nativeNumTokensIndexed = 8;
+ final int nativeNumTokensClipped = 9;
+
+ final GeneralStats gStats =
+ new GeneralStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE)
+ .setStatusCode(TEST_STATUS_CODE)
+ .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
+ .build();
+ final PutDocumentStats pStats =
+ new PutDocumentStats.Builder(gStats)
+ .setGenerateDocumentProtoLatencyMillis(generateDocumentProtoLatencyMillis)
+ .setRewriteDocumentTypesLatencyMillis(rewriteDocumentTypesLatencyMillis)
+ .setNativeLatencyMillis(nativeLatencyMillis)
+ .setNativeDocumentStoreLatencyMillis(nativeDocumentStoreLatencyMillis)
+ .setNativeIndexLatencyMillis(nativeIndexLatencyMillis)
+ .setNativeIndexMergeLatencyMillis(nativeIndexMergeLatencyMillis)
+ .setNativeDocumentSizeBytes(nativeDocumentSize)
+ .setNativeNumTokensIndexed(nativeNumTokensIndexed)
+ .setNativeNumTokensClipped(nativeNumTokensClipped)
+ .build();
+
+ assertThat(pStats.getGeneralStats().getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ assertThat(pStats.getGeneralStats().getDatabase()).isEqualTo(TEST_DATA_BASE);
+ assertThat(pStats.getGeneralStats().getStatusCode()).isEqualTo(TEST_STATUS_CODE);
+ assertThat(pStats.getGeneralStats().getTotalLatencyMillis())
+ .isEqualTo(TEST_TOTAL_LATENCY_MILLIS);
+ assertThat(pStats.getGenerateDocumentProtoLatencyMillis())
+ .isEqualTo(generateDocumentProtoLatencyMillis);
+ assertThat(pStats.getRewriteDocumentTypesLatencyMillis())
+ .isEqualTo(rewriteDocumentTypesLatencyMillis);
+ assertThat(pStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(pStats.getNativeDocumentStoreLatencyMillis())
+ .isEqualTo(nativeDocumentStoreLatencyMillis);
+ assertThat(pStats.getNativeIndexLatencyMillis()).isEqualTo(nativeIndexLatencyMillis);
+ assertThat(pStats.getNativeIndexMergeLatencyMillis())
+ .isEqualTo(nativeIndexMergeLatencyMillis);
+ assertThat(pStats.getNativeDocumentSizeBytes()).isEqualTo(nativeDocumentSize);
+ assertThat(pStats.getNativeNumTokensIndexed()).isEqualTo(nativeNumTokensIndexed);
+ assertThat(pStats.getNativeNumTokensClipped()).isEqualTo(nativeNumTokensClipped);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
index b98f0257d7b7..205ff300c543 100644
--- a/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -23,6 +23,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
+import android.app.backup.BackupAgent;
import android.app.backup.BackupManager.OperationType;
import android.app.backup.IBackupManagerMonitor;
import android.app.backup.IBackupObserver;
@@ -30,6 +31,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import com.android.internal.backup.IBackupTransport;
import android.platform.test.annotations.Presubmit;
import androidx.test.runner.AndroidJUnit4;
@@ -56,6 +58,7 @@ public class UserBackupManagerServiceTest {
@Mock IBackupObserver mBackupObserver;
@Mock PackageManager mPackageManager;
@Mock TransportClient mTransportClient;
+ @Mock IBackupTransport mBackupTransport;
@Mock BackupEligibilityRules mBackupEligibilityRules;
@@ -132,6 +135,33 @@ public class UserBackupManagerServiceTest {
assertThat(params.mBackupEligibilityRules).isEqualTo(mBackupEligibilityRules);
}
+ @Test
+ public void testGetOperationTypeFromTransport_returnsBackupByDefault()
+ throws Exception {
+ when(mTransportClient.connectOrThrow(any())).thenReturn(mBackupTransport);
+ when(mBackupTransport.getTransportFlags()).thenReturn(0);
+
+ int operationType = mService.getOperationTypeFromTransport(mTransportClient);
+
+ assertThat(operationType).isEqualTo(OperationType.BACKUP);
+ }
+
+ @Test
+ public void testGetOperationTypeFromTransport_returnsMigrationForMigrationTransport()
+ throws Exception {
+ // This is a temporary flag to control the new behaviour until it's ready to be fully
+ // rolled out.
+ mService.shouldUseNewBackupEligibilityRules = true;
+
+ when(mTransportClient.connectOrThrow(any())).thenReturn(mBackupTransport);
+ when(mBackupTransport.getTransportFlags()).thenReturn(
+ BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER);
+
+ int operationType = mService.getOperationTypeFromTransport(mTransportClient);
+
+ assertThat(operationType).isEqualTo(OperationType.MIGRATION);
+ }
+
private static PackageInfo getPackageInfo(String packageName) {
PackageInfo packageInfo = new PackageInfo();
packageInfo.applicationInfo = new ApplicationInfo();
@@ -141,6 +171,7 @@ public class UserBackupManagerServiceTest {
private static class TestBackupService extends UserBackupManagerService {
boolean isEnabledStatePersisted = false;
+ boolean shouldUseNewBackupEligibilityRules = false;
TestBackupService(Context context, PackageManager packageManager) {
super(context, packageManager);
@@ -158,5 +189,10 @@ public class UserBackupManagerServiceTest {
@Override
void updateStateOnBackupEnabled(boolean wasEnabled, boolean enable) {}
+
+ @Override
+ boolean shouldUseNewBackupEligibilityRules() {
+ return shouldUseNewBackupEligibilityRules;
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
index 2cbc3f381909..a694d5e37566 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
@@ -153,4 +153,25 @@ public class SyncOperationTest extends AndroidTestCase {
assertEquals("Period not restored", periodic.periodMillis, oneoff.periodMillis);
assertEquals("Flex not restored", periodic.flexMillis, oneoff.flexMillis);
}
+
+ @SmallTest
+ public void testScheduleAsEjIsInExtras() {
+ Account account1 = new Account("account1", "type1");
+ Bundle b1 = new Bundle();
+ b1.putBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, true);
+
+ SyncOperation op1 = new SyncOperation(account1, 0, 1, "foo", 0,
+ SyncOperation.REASON_USER_START, "authority1", b1, false,
+ ContentResolver.SYNC_EXEMPTION_NONE);
+ assertTrue(op1.isScheduledAsExpeditedJob());
+
+ PersistableBundle pb = op1.toJobInfoExtras();
+ assertTrue("EJ extra not found in job extras",
+ ((PersistableBundle) pb.get("syncExtras"))
+ .containsKey(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB));
+
+ SyncOperation op2 = SyncOperation.maybeCreateFromJobExtras(pb);
+ assertTrue("EJ extra not found in extras", op2.getClonedExtras()
+ .getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 6add8d18aa3e..87100a63e35e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -20,6 +20,8 @@ import static android.app.Notification.EXTRA_TITLE;
import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;
import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI;
import static android.app.admin.DevicePolicyManager.ID_TYPE_MEID;
@@ -826,7 +828,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
* {@link DevicePolicyManager#forceRemoveActiveAdmin(ComponentName, int)}
*/
@Test
- public void testForceRemoveActiveAdmin() throws Exception {
+ public void testForceRemoveActiveAdmin_nonShellCaller() throws Exception {
mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
// Add admin.
@@ -840,8 +842,53 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Calling from a non-shell uid should fail with a SecurityException
mContext.binder.callingUid = 123456;
assertExpectException(SecurityException.class,
- /* messageRegex =*/ "Non-shell user attempted to call",
+ /* messageRegex = */ null,
() -> dpms.forceRemoveActiveAdmin(admin1, CALLER_USER_HANDLE));
+ }
+
+ /**
+ * Test for:
+ * {@link DevicePolicyManager#forceRemoveActiveAdmin(ComponentName, int)}
+ */
+ @Test
+ public void testForceRemoveActiveAdmin_nonShellCallerWithPermission() throws Exception {
+ mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+ // Add admin.
+ setupPackageInPackageManager(admin1.getPackageName(),
+ /* userId= */ CALLER_USER_HANDLE,
+ /* appId= */ 10138,
+ /* flags= */ ApplicationInfo.FLAG_TEST_ONLY);
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+ assertThat(dpm.isAdminActive(admin1)).isTrue();
+
+ mContext.binder.callingUid = 123456;
+ mContext.callerPermissions.add(
+ android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+ dpms.forceRemoveActiveAdmin(admin1, CALLER_USER_HANDLE);
+
+ mContext.callerPermissions.add(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ // Verify
+ assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse();
+ verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+ null, CALLER_USER_HANDLE);
+ }
+
+ /**
+ * Test for:
+ * {@link DevicePolicyManager#forceRemoveActiveAdmin(ComponentName, int)}
+ */
+ @Test
+ public void testForceRemoveActiveAdmin_ShellCaller() throws Exception {
+ mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+ // Add admin.
+ setupPackageInPackageManager(admin1.getPackageName(),
+ /* userId= */ CALLER_USER_HANDLE,
+ /* appId= */ 10138,
+ /* flags= */ ApplicationInfo.FLAG_TEST_ONLY);
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+ assertThat(dpm.isAdminActive(admin1)).isTrue();
mContext.binder.callingUid = Process.SHELL_UID;
dpms.forceRemoveActiveAdmin(admin1, CALLER_USER_HANDLE);
@@ -7028,6 +7075,71 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ public void testSetDeviceOwnerType_throwsExceptionWhenCallerNotAuthorized() {
+ assertThrows(SecurityException.class,
+ () -> dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_DEFAULT));
+ }
+
+ @Test
+ public void testSetDeviceOwnerType_throwsExceptionWhenThereIsNoDeviceOwner() {
+ mContext.binder.clearCallingIdentity();
+ assertThrows(IllegalStateException.class,
+ () -> dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_DEFAULT));
+ }
+
+ @Test
+ public void testSetDeviceOwnerType_throwsExceptionWhenNotAsDeviceOwnerAdmin() throws Exception {
+ setDeviceOwner();
+
+ assertThrows(IllegalStateException.class,
+ () -> dpm.setDeviceOwnerType(admin2, DEVICE_OWNER_TYPE_FINANCED));
+ }
+
+ @Test
+ public void testSetDeviceOwnerType_asDeviceOwner_toFinancedDevice() throws Exception {
+ setDeviceOwner();
+
+ dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);
+
+ int returnedDeviceOwnerType = dpm.getDeviceOwnerType(admin1);
+ assertThat(dpms.mOwners.hasDeviceOwner()).isTrue();
+ assertThat(returnedDeviceOwnerType).isEqualTo(DEVICE_OWNER_TYPE_FINANCED);
+
+ initializeDpms();
+
+ returnedDeviceOwnerType = dpm.getDeviceOwnerType(admin1);
+ assertThat(dpms.mOwners.hasDeviceOwner()).isTrue();
+ assertThat(returnedDeviceOwnerType).isEqualTo(DEVICE_OWNER_TYPE_FINANCED);
+ }
+
+ @Test
+ public void testSetDeviceOwnerType_asDeviceOwner_throwsExceptionWhenSetDeviceOwnerTypeAgain()
+ throws Exception {
+ setDeviceOwner();
+
+ dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);
+
+ int returnedDeviceOwnerType = dpm.getDeviceOwnerType(admin1);
+ assertThat(dpms.mOwners.hasDeviceOwner()).isTrue();
+ assertThat(returnedDeviceOwnerType).isEqualTo(DEVICE_OWNER_TYPE_FINANCED);
+
+ assertThrows(IllegalStateException.class,
+ () -> dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_DEFAULT));
+ }
+
+ @Test
+ public void testGetDeviceOwnerType_throwsExceptionWhenThereIsNoDeviceOwner() {
+ assertThrows(IllegalStateException.class, () -> dpm.getDeviceOwnerType(admin1));
+ }
+
+ @Test
+ public void testGetDeviceOwnerType_throwsExceptionWhenNotAsDeviceOwnerAdmin() throws Exception {
+ setDeviceOwner();
+
+ assertThrows(IllegalStateException.class, () -> dpm.getDeviceOwnerType(admin2));
+ }
+
+ @Test
public void testSetUsbDataSignalingEnabled_noDeviceOwnerOrPoOfOrgOwnedDevice() {
assertThrows(SecurityException.class,
() -> dpm.setUsbDataSignalingEnabled(true));
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
index bfe183cc608b..39ca925d0115 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
@@ -16,6 +16,9 @@
package com.android.server.devicepolicy;
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
+
import static com.google.common.truth.Truth.assertThat;
import android.content.ComponentName;
@@ -35,7 +38,6 @@ import org.junit.runner.RunWith;
* <p>Run this test with:
*
* {@code atest FrameworksServicesTests:com.android.server.devicepolicy.OwnersTest}
- *
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -67,6 +69,8 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.hasDeviceOwner()).isFalse();
assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_DEFAULT);
assertThat(owners.getSystemUpdatePolicy()).isNull();
assertThat(owners.getProfileOwnerKeys()).isEmpty();
@@ -75,6 +79,12 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse();
assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
+
+ owners.setDeviceOwnerType(owners.getDeviceOwnerPackageName(),
+ DEVICE_OWNER_TYPE_FINANCED);
+ // There is no device owner, so the default owner type should be returned.
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_DEFAULT);
}
// Then re-read and check.
@@ -84,6 +94,8 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.hasDeviceOwner()).isFalse();
assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_DEFAULT);
assertThat(owners.getSystemUpdatePolicy()).isNull();
assertThat(owners.getProfileOwnerKeys()).isEmpty();
@@ -122,6 +134,8 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.getDeviceOwnerName()).isEqualTo(null);
assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc");
assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_DEFAULT);
assertThat(owners.getSystemUpdatePolicy()).isNull();
assertThat(owners.getProfileOwnerKeys()).isEmpty();
@@ -142,6 +156,8 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.getDeviceOwnerName()).isEqualTo(null);
assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc");
assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_DEFAULT);
assertThat(owners.getSystemUpdatePolicy()).isNull();
assertThat(owners.getProfileOwnerKeys()).isEmpty();
@@ -180,6 +196,8 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.hasDeviceOwner()).isFalse();
assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
assertThat(owners.getSystemUpdatePolicy()).isNull();
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_DEFAULT);
assertThat(owners.getProfileOwnerKeys()).hasSize(2);
assertThat(owners.getProfileOwnerComponent(10))
@@ -208,6 +226,8 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.hasDeviceOwner()).isFalse();
assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
assertThat(owners.getSystemUpdatePolicy()).isNull();
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_DEFAULT);
assertThat(owners.getProfileOwnerKeys()).hasSize(2);
assertThat(owners.getProfileOwnerComponent(10))
@@ -260,6 +280,8 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.getDeviceOwnerName()).isEqualTo(null);
assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc");
assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_DEFAULT);
assertThat(owners.getSystemUpdatePolicy()).isNotNull();
assertThat(owners.getSystemUpdatePolicy().getPolicyType()).isEqualTo(5);
@@ -292,6 +314,8 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.getDeviceOwnerName()).isEqualTo(null);
assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc");
assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_DEFAULT);
assertThat(owners.getSystemUpdatePolicy()).isNotNull();
assertThat(owners.getSystemUpdatePolicy().getPolicyType()).isEqualTo(5);
@@ -315,12 +339,21 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
owners.setDeviceOwnerUserRestrictionsMigrated();
+
+ owners.setDeviceOwnerType(owners.getDeviceOwnerPackageName(),
+ DEVICE_OWNER_TYPE_FINANCED);
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_FINANCED);
}
{
final OwnersTestable owners = new OwnersTestable(getServices());
owners.load();
+ assertThat(owners.hasDeviceOwner()).isTrue();
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_FINANCED);
+
assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue();
assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isTrue();
@@ -328,12 +361,22 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
owners.setProfileOwnerUserRestrictionsMigrated(11);
+
+ owners.setDeviceOwnerType(owners.getDeviceOwnerPackageName(),
+ DEVICE_OWNER_TYPE_DEFAULT);
+ // The previous device owner type should persist.
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_FINANCED);
}
{
final OwnersTestable owners = new OwnersTestable(getServices());
owners.load();
+ assertThat(owners.hasDeviceOwner()).isTrue();
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_FINANCED);
+
assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue();
assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse();
@@ -369,6 +412,8 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.hasDeviceOwner()).isFalse();
assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_DEFAULT);
assertThat(owners.getSystemUpdatePolicy()).isNull();
@@ -388,6 +433,8 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.hasDeviceOwner()).isFalse();
assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_DEFAULT);
assertThat(owners.getSystemUpdatePolicy()).isNull();
@@ -425,6 +472,8 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.hasDeviceOwner()).isFalse();
assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_DEFAULT);
assertThat(owners.getProfileOwnerKeys()).isEmpty();
assertThat(owners.getSystemUpdatePolicy()).isNotNull();
@@ -444,6 +493,8 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.hasDeviceOwner()).isFalse();
assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_DEFAULT);
assertThat(owners.getProfileOwnerKeys()).isEmpty();
assertThat(owners.getSystemUpdatePolicy()).isNotNull();
@@ -472,9 +523,16 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.getLegacyConfigFile().exists()).isFalse();
assertThat(owners.getDeviceOwnerFile().exists()).isTrue();
+ assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+ DEVICE_OWNER_TYPE_DEFAULT);
assertThat(owners.getProfileOwnerFile(10).exists()).isTrue();
assertThat(owners.getProfileOwnerFile(11).exists()).isTrue();
+ String previousDeviceOwnerPackageName = owners.getDeviceOwnerPackageName();
+ owners.setDeviceOwnerType(previousDeviceOwnerPackageName, DEVICE_OWNER_TYPE_FINANCED);
+ assertThat(owners.getDeviceOwnerType(previousDeviceOwnerPackageName)).isEqualTo(
+ DEVICE_OWNER_TYPE_FINANCED);
+
// Then clear all information and save.
owners.clearDeviceOwner();
owners.clearSystemUpdatePolicy();
@@ -491,5 +549,8 @@ public class OwnersTest extends DpmTestBase {
assertThat(owners.getDeviceOwnerFile().exists()).isFalse();
assertThat(owners.getProfileOwnerFile(10).exists()).isFalse();
assertThat(owners.getProfileOwnerFile(11).exists()).isFalse();
+
+ assertThat(owners.getDeviceOwnerType(previousDeviceOwnerPackageName)).isEqualTo(
+ DEVICE_OWNER_TYPE_DEFAULT);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 1c55072cab2c..bc86d1d39b1c 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -993,7 +993,7 @@ public class DisplayManagerServiceTest {
private DisplayDeviceInfo mDisplayDeviceInfo;
FakeDisplayDevice() {
- super(null, null, "");
+ super(null, null, "", mContext);
}
public void setDisplayDeviceInfo(DisplayDeviceInfo displayDeviceInfo) {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
index f49cbca12fd8..9bf95c0edcdb 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
@@ -221,7 +221,8 @@ public class DeviceSelectActionTest {
"testDeviceSelect");
action.start();
mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).doesNotContain(SET_STREAM_PATH);
+ assertThat(mNativeWrapper.getResultMessages()).contains(SET_STREAM_PATH);
+ mNativeWrapper.clearResultMessages();
assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
action.processCommand(REPORT_POWER_STATUS_ON);
mTestLooper.dispatchAll();
@@ -238,12 +239,15 @@ public class DeviceSelectActionTest {
DeviceSelectAction action = createDeviceSelectAction(actionTimer, callback,
/*isCec20=*/false);
action.start();
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(SET_STREAM_PATH);
assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
action.processCommand(REPORT_POWER_STATUS_STANDBY);
mTestLooper.dispatchAll();
HdmiCecMessage userControlPressed = HdmiCecMessageBuilder.buildUserControlPressed(
ADDR_TV, ADDR_PLAYBACK_1, HdmiCecKeycode.CEC_KEYCODE_POWER);
assertThat(mNativeWrapper.getResultMessages()).contains(userControlPressed);
+ mNativeWrapper.clearResultMessages();
assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_DEVICE_POWER_ON);
action.handleTimerEvent(STATE_WAIT_FOR_DEVICE_POWER_ON);
action.processCommand(REPORT_POWER_STATUS_ON);
@@ -261,6 +265,9 @@ public class DeviceSelectActionTest {
DeviceSelectAction action = createDeviceSelectAction(actionTimer, callback,
/*isCec20=*/false);
action.start();
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(SET_STREAM_PATH);
+ mNativeWrapper.clearResultMessages();
assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
action.processCommand(REPORT_POWER_STATUS_STANDBY);
assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_DEVICE_POWER_ON);
@@ -285,6 +292,9 @@ public class DeviceSelectActionTest {
DeviceSelectAction action = createDeviceSelectAction(actionTimer, callback,
/*isCec20=*/false);
action.start();
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(SET_STREAM_PATH);
+ mNativeWrapper.clearResultMessages();
assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
action.processCommand(REPORT_POWER_STATUS_STANDBY);
assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_DEVICE_POWER_ON);
@@ -330,8 +340,11 @@ public class DeviceSelectActionTest {
action.start();
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(SET_STREAM_PATH);
+ mNativeWrapper.clearResultMessages();
assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
action.processCommand(REPORT_POWER_STATUS_ON);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(SET_STREAM_PATH);
assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
}
@@ -354,9 +367,12 @@ public class DeviceSelectActionTest {
HdmiCecMessage userControlPressed = HdmiCecMessageBuilder.buildUserControlPressed(
ADDR_TV, ADDR_PLAYBACK_1, HdmiCecKeycode.CEC_KEYCODE_POWER);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(userControlPressed);
+ mNativeWrapper.clearResultMessages();
assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_DEVICE_POWER_ON);
action.handleTimerEvent(STATE_WAIT_FOR_DEVICE_POWER_ON);
action.processCommand(REPORT_POWER_STATUS_ON);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(SET_STREAM_PATH);
assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 462f3e32ab3b..32a70480c39e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -485,17 +485,6 @@ public class HdmiControlServiceTest {
}
@Test
- public void getCecVersion_default() {
- // Set the Settings value to "null" to emulate it being empty and force the default value.
- Settings.Global.putString(mContextSpy.getContentResolver(),
- Settings.Global.HDMI_CEC_VERSION,
- null);
- mHdmiControlService.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
- assertThat(mHdmiControlService.getCecVersion()).isEqualTo(
- HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
- }
-
- @Test
public void getCecVersion_1_4() {
mHdmiControlService.getHdmiCecConfig().setIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
diff --git a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
index 3e9709d55268..f0a9a0089ec9 100644
--- a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
@@ -31,6 +31,7 @@ import android.hardware.light.ILights;
import android.hardware.lights.Light;
import android.hardware.lights.LightState;
import android.hardware.lights.LightsManager;
+import android.hardware.lights.SystemLightsManager;
import android.os.Looper;
import androidx.test.filters.SmallTest;
@@ -93,7 +94,7 @@ public class LightsServiceTest {
@Test
public void testGetLights_filtersSystemLights() {
LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper());
- LightsManager manager = new LightsManager(mContext, service.mManagerService);
+ LightsManager manager = new SystemLightsManager(mContext, service.mManagerService);
// When lights are listed, only the 4 MICROPHONE lights should be visible.
assertThat(manager.getLights().size()).isEqualTo(4);
@@ -102,14 +103,14 @@ public class LightsServiceTest {
@Test
public void testControlMultipleLights() {
LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper());
- LightsManager manager = new LightsManager(mContext, service.mManagerService);
+ LightsManager manager = new SystemLightsManager(mContext, service.mManagerService);
// When the session requests to turn 3/4 lights on:
LightsManager.LightsSession session = manager.openSession();
session.requestLights(new Builder()
- .setLight(manager.getLights().get(0), new LightState(0xf1))
- .setLight(manager.getLights().get(1), new LightState(0xf2))
- .setLight(manager.getLights().get(2), new LightState(0xf3))
+ .addLight(manager.getLights().get(0), new LightState(0xf1))
+ .addLight(manager.getLights().get(1), new LightState(0xf2))
+ .addLight(manager.getLights().get(2), new LightState(0xf3))
.build());
// Then all 3 should turn on.
@@ -122,9 +123,9 @@ public class LightsServiceTest {
}
@Test
- public void testControlLights_onlyEffectiveForLifetimeOfClient() {
+ public void testControlLights_onlyEffectiveForLifetimeOfClient() throws Exception {
LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper());
- LightsManager manager = new LightsManager(mContext, service.mManagerService);
+ LightsManager manager = new SystemLightsManager(mContext, service.mManagerService);
Light micLight = manager.getLights().get(0);
// The light should begin by being off.
@@ -132,38 +133,41 @@ public class LightsServiceTest {
// When a session commits changes:
LightsManager.LightsSession session = manager.openSession();
- session.requestLights(new Builder().setLight(micLight, new LightState(GREEN)).build());
+ session.requestLights(new Builder().addLight(micLight, new LightState(GREEN)).build());
// Then the light should turn on.
assertThat(manager.getLightState(micLight).getColor()).isEqualTo(GREEN);
// When the session goes away:
session.close();
+
// Then the light should turn off.
assertThat(manager.getLightState(micLight).getColor()).isEqualTo(TRANSPARENT);
}
@Test
- public void testControlLights_firstCallerWinsContention() {
+ public void testControlLights_firstCallerWinsContention() throws Exception {
LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper());
- LightsManager manager = new LightsManager(mContext, service.mManagerService);
+ LightsManager manager = new SystemLightsManager(mContext, service.mManagerService);
Light micLight = manager.getLights().get(0);
LightsManager.LightsSession session1 = manager.openSession();
LightsManager.LightsSession session2 = manager.openSession();
// When session1 and session2 both request the same light:
- session1.requestLights(new Builder().setLight(micLight, new LightState(BLUE)).build());
- session2.requestLights(new Builder().setLight(micLight, new LightState(WHITE)).build());
+ session1.requestLights(new Builder().addLight(micLight, new LightState(BLUE)).build());
+ session2.requestLights(new Builder().addLight(micLight, new LightState(WHITE)).build());
// Then session1 should win because it was created first.
assertThat(manager.getLightState(micLight).getColor()).isEqualTo(BLUE);
// When session1 goes away:
session1.close();
+
// Then session2 should have its request go into effect.
assertThat(manager.getLightState(micLight).getColor()).isEqualTo(WHITE);
// When session2 goes away:
session2.close();
+
// Then the light should turn off because there are no more sessions.
assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0);
}
@@ -171,12 +175,12 @@ public class LightsServiceTest {
@Test
public void testClearLight() {
LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper());
- LightsManager manager = new LightsManager(mContext, service.mManagerService);
+ LightsManager manager = new SystemLightsManager(mContext, service.mManagerService);
Light micLight = manager.getLights().get(0);
// When the session turns a light on:
LightsManager.LightsSession session = manager.openSession();
- session.requestLights(new Builder().setLight(micLight, new LightState(WHITE)).build());
+ session.requestLights(new Builder().addLight(micLight, new LightState(WHITE)).build());
// And then the session clears it again:
session.requestLights(new Builder().clearLight(micLight).build());
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 7d7af03ecd3d..74bf4f5da70d 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -115,7 +115,6 @@ import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkPolicy;
-import android.net.NetworkPolicyManager;
import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
@@ -386,8 +385,7 @@ public class NetworkPolicyManagerServiceTest {
Log.d(TAG, "set mUidObserver to " + mUidObserver);
return null;
}
- }).when(mActivityManager).registerUidObserver(any(), anyInt(),
- eq(NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE), any(String.class));
+ }).when(mActivityManager).registerUidObserver(any(), anyInt(), anyInt(), any(String.class));
mFutureIntent = newRestrictBackgroundChangedFuture();
mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager,
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index ff43da6370e8..ee0a16a70265 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -86,6 +86,7 @@ public class DexManagerTests {
private TestData mBarUser0DelegateLastClassLoader;
private TestData mSystemServerJar;
+ private TestData mSystemServerJarUpdatedContext;
private TestData mSystemServerJarInvalid;
private int mUser0;
@@ -113,6 +114,8 @@ public class DexManagerTests {
mSystemServerJar = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME);
mSystemServerJarInvalid = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME);
+ mSystemServerJarUpdatedContext = new TestData("android", isa, mUser0,
+ DELEGATE_LAST_CLASS_LOADER_NAME);
mDexManager = new DexManager(/*Context*/ null, mPM, /*PackageDexOptimizer*/ null,
mInstaller, mInstallLock);
@@ -522,6 +525,24 @@ public class DexManagerTests {
}
@Test
+ public void testSystemServerOverwritesContext() {
+ // Record bar secondaries with the default PathClassLoader.
+ List<String> secondaries = mSystemServerJar.getSecondaryDexPaths();
+
+ notifyDexLoad(mSystemServerJar, secondaries, mUser0);
+ PackageUseInfo pui = getPackageUseInfo(mSystemServerJar);
+ assertSecondaryUse(mSystemServerJar, pui, secondaries, /*isUsedByOtherApps*/false, mUser0);
+
+ // Record bar secondaries again with a different class loader. This will change the context.
+ notifyDexLoad(mSystemServerJarUpdatedContext, secondaries, mUser0);
+
+ pui = getPackageUseInfo(mSystemServerJar);
+ // We expect that all the contexts to be updated according to the last notify.
+ assertSecondaryUse(mSystemServerJarUpdatedContext, pui, secondaries,
+ /*isUsedByOtherApps*/false, mUser0);
+ }
+
+ @Test
public void testNotifyUnsupportedClassLoaderDoesNotChangeExisting() {
List<String> secondaries = mBarUser0.getSecondaryDexPaths();
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/OWNERS b/services/tests/servicestests/src/com/android/server/pm/dex/OWNERS
new file mode 100644
index 000000000000..66ef75d6c823
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/dex/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
index adf4551e79a8..3450710f60a0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
@@ -451,7 +451,7 @@ public class PackageDexUsageTests {
"PCL[new_context.dex]");
assertTrue(record(fooSecondary1User0NewContext));
- // Not check that the context was switch to variable.
+ // Now check that the context was switch to variable.
TestData expectedContext = mFooSecondary1User0.updateClassLoaderContext(
PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT);
@@ -461,6 +461,22 @@ public class PackageDexUsageTests {
}
@Test
+ public void testRecordClassLoaderContextOverwritten() {
+ // Record a secondary dex file.
+ assertTrue(record(mFooSecondary1User0));
+ // Now update its context.
+ TestData fooSecondary1User0NewContext = mFooSecondary1User0.updateClassLoaderContext(
+ "PCL[new_context.dex]", true);
+ assertTrue(record(fooSecondary1User0NewContext));
+
+ // Now check that the context was overwritten.
+ TestData expectedContext = mFooSecondary1User0.updateClassLoaderContext(
+ "PCL[new_context.dex]", true);
+
+ assertPackageDexUsage(null, expectedContext);
+ }
+
+ @Test
public void testDexUsageClassLoaderContext() {
final boolean isUsedByOtherApps = false;
final int userId = 0;
@@ -642,8 +658,9 @@ public class PackageDexUsageTests {
private boolean record(TestData testData) {
return mPackageDexUsage.record(testData.mPackageName, testData.mDexFile,
- testData.mOwnerUserId, testData.mLoaderIsa,
- testData.mPrimaryOrSplit, testData.mUsedBy, testData.mClassLoaderContext);
+ testData.mOwnerUserId, testData.mLoaderIsa,
+ testData.mPrimaryOrSplit, testData.mUsedBy, testData.mClassLoaderContext,
+ testData.mOverwriteCLC);
}
private boolean record(PackageDexUsage packageDexUsage, TestData testData, Set<String> users) {
@@ -651,7 +668,8 @@ public class PackageDexUsageTests {
for (String user : users) {
result = result && packageDexUsage.record(testData.mPackageName, testData.mDexFile,
testData.mOwnerUserId, testData.mLoaderIsa,
- testData.mPrimaryOrSplit, user, testData.mClassLoaderContext);
+ testData.mPrimaryOrSplit, user, testData.mClassLoaderContext,
+ testData.mOverwriteCLC);
}
return result;
}
@@ -682,15 +700,16 @@ public class PackageDexUsageTests {
private final boolean mPrimaryOrSplit;
private final String mUsedBy;
private final String mClassLoaderContext;
+ private final boolean mOverwriteCLC;
private TestData(String packageName, String dexFile, int ownerUserId,
String loaderIsa, boolean primaryOrSplit, String usedBy) {
this(packageName, dexFile, ownerUserId, loaderIsa, primaryOrSplit,
- usedBy, "PCL[" + dexFile + "]");
+ usedBy, "PCL[" + dexFile + "]", false);
}
private TestData(String packageName, String dexFile, int ownerUserId,
String loaderIsa, boolean primaryOrSplit, String usedBy,
- String classLoaderContext) {
+ String classLoaderContext, boolean overwriteCLC) {
mPackageName = packageName;
mDexFile = dexFile;
mOwnerUserId = ownerUserId;
@@ -698,16 +717,21 @@ public class PackageDexUsageTests {
mPrimaryOrSplit = primaryOrSplit;
mUsedBy = usedBy;
mClassLoaderContext = classLoaderContext;
+ mOverwriteCLC = overwriteCLC;
}
private TestData updateClassLoaderContext(String newContext) {
+ return updateClassLoaderContext(newContext, mOverwriteCLC);
+ }
+
+ private TestData updateClassLoaderContext(String newContext, boolean overwriteCLC) {
return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa,
- mPrimaryOrSplit, mUsedBy, newContext);
+ mPrimaryOrSplit, mUsedBy, newContext, overwriteCLC);
}
private TestData updateUsedBy(String newUsedBy) {
return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa,
- mPrimaryOrSplit, newUsedBy, mClassLoaderContext);
+ mPrimaryOrSplit, newUsedBy, mClassLoaderContext, mOverwriteCLC);
}
private boolean isUsedByOtherApps() {
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 6b95cfc934ac..ea27331ac4ca 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -98,9 +98,11 @@ import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Tests for {@link com.android.server.power.PowerManagerService}.
@@ -402,30 +404,33 @@ public class PowerManagerServiceTest {
@Test
public void testGetDesiredScreenPolicy_WithVR() throws Exception {
createService();
+ mService.systemReady(null);
// Brighten up the screen
- mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_UNKNOWN, 0);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_AWAKE, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_BRIGHT);
// Move to VR
mService.setVrModeEnabled(true);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_VR);
// Then take a nap
- mService.setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
- 0);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_OFF);
// Wake up to VR
- mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_UNKNOWN, 0);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_AWAKE, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_VR);
// And back to normal
mService.setVrModeEnabled(false);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_BRIGHT);
}
@@ -676,8 +681,9 @@ public class PowerManagerServiceTest {
}
@Test
- public void testForceSuspend_forceSuspendFailurePropogated() {
+ public void testForceSuspend_forceSuspendFailurePropagated() throws Exception {
createService();
+ startSystem();
when(mNativeWrapperMock.nativeForceSuspend()).thenReturn(false);
assertThat(mService.getBinderServiceInstance().forceSuspend()).isFalse();
}
@@ -841,7 +847,7 @@ public class PowerManagerServiceTest {
createService();
startSystem();
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_BRIGHT);
}
@@ -860,11 +866,8 @@ public class PowerManagerServiceTest {
public void testQuiescentBoot_DesiredScreenPolicyShouldBeOff() throws Exception {
when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), any())).thenReturn("1");
createService();
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
- DisplayPowerRequest.POLICY_OFF);
-
startSystem();
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_OFF);
}
@@ -874,7 +877,7 @@ public class PowerManagerServiceTest {
createService();
startSystem();
forceAwake();
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_BRIGHT);
}
@@ -890,7 +893,7 @@ public class PowerManagerServiceTest {
mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
DisplayPowerRequest.POLICY_BRIGHT);
}
@@ -1164,6 +1167,87 @@ public class PowerManagerServiceTest {
}
@Test
+ public void testMultiDisplay_wakefulnessUpdates() throws Exception {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_AWAKE, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ @Test
+ public void testMultiDisplay_addDisplayGroup_preservesWakefulness() throws Exception {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+
+ createService();
+ startSystem();
+
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ }
+
+ @Test
+ public void testMultiDisplay_removeDisplayGroup_updatesWakefulness() throws Exception {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ listener.get().onDisplayGroupRemoved(nonDefaultDisplayGroupId);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_AWAKE, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ @Test
public void testGetFullPowerSavePolicy_returnsStateMachineResult() {
createService();
mService.systemReady(null);
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 a64050996d42..cebdbbef2329 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3671,8 +3671,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.addNotification(r);
final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true);
- mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, r.getSbn().getTag(),
- r.getSbn().getId(), r.getUserId(), r.getKey(), NotificationStats.DISMISSAL_AOD,
+ mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, r.getUserId(),
+ r.getKey(), NotificationStats.DISMISSAL_AOD,
NotificationStats.DISMISS_SENTIMENT_POSITIVE, nv);
waitForIdle();
@@ -3694,8 +3694,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.addNotification(r);
final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true);
- mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, r.getSbn().getTag(),
- r.getSbn().getId(), r.getUserId(), r.getKey(), NotificationStats.DISMISSAL_AOD,
+ mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, r.getUserId(),
+ r.getKey(), NotificationStats.DISMISSAL_AOD,
NotificationStats.DISMISS_SENTIMENT_NEGATIVE, nv);
waitForIdle();
@@ -6693,8 +6693,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2,
true);
mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG,
- nrSummary.getSbn().getTag(),
- nrSummary.getSbn().getId(), nrSummary.getUserId(), nrSummary.getKey(),
+ nrSummary.getUserId(), nrSummary.getKey(),
NotificationStats.DISMISSAL_SHADE,
NotificationStats.DISMISS_SENTIMENT_NEUTRAL, nv);
waitForIdle();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 35b224a24061..2ae2ef7162a5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -51,6 +51,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.UiServiceTestCase;
+import com.android.server.pm.PackageManagerService;
import org.junit.Before;
import org.junit.Test;
@@ -259,6 +260,17 @@ public class SnoozeHelperTest extends UiServiceTestCase {
}
@Test
+ public void testSnoozeSentToAndroid() throws Exception {
+ NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ mSnoozeHelper.snooze(r, 1000);
+ ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class);
+ verify(mAm, times(1)).setExactAndAllowWhileIdle(
+ anyInt(), anyLong(), captor.capture());
+ assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME,
+ captor.getValue().getIntent().getPackage());
+ }
+
+ @Test
public void testSnooze() throws Exception {
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
mSnoozeHelper.snooze(r, (String) null);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index aa1110cd55a7..488e629f5790 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2288,7 +2288,7 @@ public class ActivityRecordTests extends WindowTestsBase {
IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
reset(task);
activity.reportDescendantOrientationChangeIfNeeded();
- verify(task).onConfigurationChanged(any(Configuration.class));
+ verify(task, atLeast(1)).onConfigurationChanged(any(Configuration.class));
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
index d13e4dcaf9fd..7df17fd4b3c6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
@@ -38,6 +38,7 @@ import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION
import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
import static com.android.server.wm.DisplayAreaPolicyBuilder.Feature;
+import static com.android.server.wm.DisplayAreaPolicyBuilder.KEY_ROOT_DISPLAY_AREA_ID;
import static com.google.common.truth.Truth.assertThat;
@@ -595,6 +596,17 @@ public class DisplayAreaPolicyBuilderTest {
assertThat(token.isDescendantOf(mRoot)).isTrue();
assertThat(token.isDescendantOf(mGroupRoot1)).isFalse();
assertThat(token.isDescendantOf(mGroupRoot2)).isFalse();
+
+ // When the window has options for target root id, attach it to the target root.
+ final Bundle options = new Bundle();
+ options.putInt(KEY_ROOT_DISPLAY_AREA_ID, mGroupRoot2.mFeatureId);
+ final WindowToken token2 = new WindowToken(mWms, mock(IBinder.class),
+ TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, false /* roundedCornerOverlay */,
+ false /* fromClientToken */, options);
+ policy.addWindow(token2);
+
+ assertThat(token2.isDescendantOf(mGroupRoot2)).isTrue();
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 58169bb1e073..137cf6523caf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -32,6 +32,8 @@ import static android.view.DisplayCutout.fromBoundingRect;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
@@ -121,6 +123,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.utils.WmDisplayCutout;
import org.junit.Test;
@@ -955,16 +958,14 @@ public class DisplayContentTests extends WindowTestsBase {
IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
final int newOrientation = getRotatedOrientation(dc);
- final Task stack = new TaskBuilder(mSupervisor)
+ final Task task = new TaskBuilder(mSupervisor)
.setDisplay(dc).setCreateActivity(true).build();
- final ActivityRecord activity = stack.getTopMostTask().getTopNonFinishingActivity();
+ final ActivityRecord activity = task.getTopMostTask().getTopNonFinishingActivity();
+ dc.setFocusedApp(activity);
activity.setRequestedOrientation(newOrientation);
- final int expectedOrientation = newOrientation == SCREEN_ORIENTATION_PORTRAIT
- ? Configuration.ORIENTATION_PORTRAIT
- : Configuration.ORIENTATION_LANDSCAPE;
- assertEquals(expectedOrientation, dc.getConfiguration().orientation);
+ assertTrue("The display should be rotated.", dc.getRotation() % 2 == 1);
}
@Test
@@ -972,17 +973,42 @@ public class DisplayContentTests extends WindowTestsBase {
final DisplayContent dc = createNewDisplay();
dc.getDisplayRotation().setFixedToUserRotation(
IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
+ dc.getDisplayRotation().setUserRotation(
+ WindowManagerPolicy.USER_ROTATION_LOCKED, ROTATION_180);
final int newOrientation = getRotatedOrientation(dc);
- final Task stack = new TaskBuilder(mSupervisor)
+ final Task task = new TaskBuilder(mSupervisor)
.setDisplay(dc).setCreateActivity(true).build();
- final ActivityRecord activity = stack.getTopMostTask().getTopNonFinishingActivity();
+ final ActivityRecord activity = task.getTopMostTask().getTopNonFinishingActivity();
+ dc.setFocusedApp(activity);
activity.setRequestedOrientation(newOrientation);
verify(dc, never()).updateDisplayOverrideConfigurationLocked(any(), eq(activity),
anyBoolean(), same(null));
- assertEquals(dc.getDisplayRotation().getUserRotation(), dc.getRotation());
+ assertEquals(ROTATION_180, dc.getRotation());
+ }
+
+ @Test
+ public void testFixedToUserRotationChanged() {
+ final DisplayContent dc = createNewDisplay();
+ dc.getDisplayRotation().setFixedToUserRotation(
+ IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
+ dc.getDisplayRotation().setUserRotation(
+ WindowManagerPolicy.USER_ROTATION_LOCKED, ROTATION_0);
+ final int newOrientation = getRotatedOrientation(dc);
+
+ final Task task = new TaskBuilder(mSupervisor)
+ .setDisplay(dc).setCreateActivity(true).build();
+ final ActivityRecord activity = task.getTopMostTask().getTopNonFinishingActivity();
+ dc.setFocusedApp(activity);
+
+ activity.setRequestedOrientation(newOrientation);
+
+ dc.getDisplayRotation().setFixedToUserRotation(
+ IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
+
+ assertTrue("The display should be rotated.", dc.getRotation() % 2 == 1);
}
@Test
@@ -1418,7 +1444,7 @@ public class DisplayContentTests extends WindowTestsBase {
// Assume the animation of PipTaskOrganizer is done and then commit fullscreen to task.
pinnedTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
displayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
- assertFalse(displayContent.getPinnedStackController().isPipActiveOrWindowingModeChanging());
+ assertFalse(displayContent.getPinnedTaskController().isPipActiveOrWindowingModeChanging());
assertEquals(pinnedConfigOrientation, displayConfig.orientation);
clearInvocations(mWm);
@@ -1429,7 +1455,7 @@ public class DisplayContentTests extends WindowTestsBase {
assertFalse(displayContent.hasTopFixedRotationLaunchingApp());
verify(mWm, atLeastOnce()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
assertEquals(homeConfigOrientation, displayConfig.orientation);
- assertTrue(displayContent.getPinnedStackController().isPipActiveOrWindowingModeChanging());
+ assertTrue(displayContent.getPinnedTaskController().isPipActiveOrWindowingModeChanging());
}
@Test
@@ -1820,6 +1846,37 @@ public class DisplayContentTests extends WindowTestsBase {
verify(t).show(mDisplayContent.mImeScreenshot);
}
+ @Test
+ public void testRotateBounds_keepSamePhysicalPosition() {
+ final DisplayContent dc =
+ new TestDisplayContent.Builder(mAtm, 1000, 2000).build();
+ final Rect initBounds = new Rect(0, 0, 700, 1500);
+ final Rect rotateBounds = new Rect(initBounds);
+
+ // Rotate from 0 to 0
+ dc.rotateBounds(ROTATION_0, ROTATION_0, rotateBounds);
+
+ assertEquals(new Rect(0, 0, 700, 1500), rotateBounds);
+
+ // Rotate from 0 to 90
+ rotateBounds.set(initBounds);
+ dc.rotateBounds(ROTATION_0, ROTATION_90, rotateBounds);
+
+ assertEquals(new Rect(0, 300, 1500, 1000), rotateBounds);
+
+ // Rotate from 0 to 180
+ rotateBounds.set(initBounds);
+ dc.rotateBounds(ROTATION_0, ROTATION_180, rotateBounds);
+
+ assertEquals(new Rect(300, 500, 1000, 2000), rotateBounds);
+
+ // Rotate from 0 to 270
+ rotateBounds.set(initBounds);
+ dc.rotateBounds(ROTATION_0, ROTATION_270, rotateBounds);
+
+ assertEquals(new Rect(500, 0, 2000, 700), rotateBounds);
+ }
+
private boolean isOptionsPanelAtRight(int displayId) {
return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 896969548af3..51aec65f7285 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -251,7 +251,7 @@ public class WindowStateTests extends WindowTestsBase {
// Simulate the window is in split screen primary stack and the current state is
// minimized and home stack is resizable, so that we should ignore input for the stack.
- final DockedStackDividerController controller =
+ final DockedTaskDividerController controller =
mDisplayContent.getDockedDividerController();
final Task stack = createTaskStackOnDisplay(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
ACTIVITY_TYPE_STANDARD, mDisplayContent);
diff --git a/services/texttospeech/Android.bp b/services/texttospeech/Android.bp
index bacc932f760f..391ab8946c2c 100644
--- a/services/texttospeech/Android.bp
+++ b/services/texttospeech/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
filegroup {
name: "services.texttospeech-sources",
srcs: ["java/**/*.java"],
@@ -10,4 +19,4 @@ java_library_static {
defaults: ["platform_service_defaults"],
srcs: [":services.texttospeech-sources"],
libs: ["services.core"],
-} \ No newline at end of file
+}
diff --git a/services/translation/Android.bp b/services/translation/Android.bp
index 804a6177e94e..f257f1b7339a 100644
--- a/services/translation/Android.bp
+++ b/services/translation/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
filegroup {
name: "services.translation-sources",
srcs: ["java/**/*.java"],
@@ -10,4 +19,4 @@ java_library_static {
defaults: ["platform_service_defaults"],
srcs: [":services.translation-sources"],
libs: ["services.core"],
-} \ No newline at end of file
+}
diff --git a/telecomm/java/android/telecom/Connection.aidl b/telecomm/java/android/telecom/Connection.aidl
new file mode 100644
index 000000000000..5b40036e46f4
--- /dev/null
+++ b/telecomm/java/android/telecom/Connection.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecom;
+
+/**
+ * {@hide}
+ */
+parcelable Connection.CallFilteringCompletionInfo;
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 942a54eb98ba..7c6253ce933a 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -29,6 +29,7 @@ import android.annotation.SystemApi;
import android.app.Notification;
import android.bluetooth.BluetoothDevice;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
import android.content.Intent;
import android.hardware.camera2.CameraManager;
import android.net.Uri;
@@ -38,7 +39,9 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcel;
import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
import android.telephony.ims.ImsStreamMediaProfile;
@@ -3379,6 +3382,121 @@ public abstract class Connection extends Conferenceable {
public void handleRttUpgradeResponse(@Nullable RttTextStream rttTextStream) {}
/**
+ * Information provided to a {@link Connection} upon completion of call filtering in Telecom.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final class CallFilteringCompletionInfo implements Parcelable {
+ private final boolean mIsBlocked;
+ private final boolean mIsInContacts;
+ private final CallScreeningService.CallResponse mCallResponse;
+ private final ComponentName mCallScreeningComponent;
+
+ /**
+ * Constructor for {@link CallFilteringCompletionInfo}
+ *
+ * @param isBlocked Whether any part of the call filtering process indicated that this call
+ * should be blocked.
+ * @param isInContacts Whether the caller is in the user's contacts.
+ * @param callResponse The instance of {@link CallScreeningService.CallResponse} provided
+ * by the {@link CallScreeningService} that processed this call, or
+ * {@code null} if no call screening service ran.
+ * @param callScreeningComponent The component of the {@link CallScreeningService}
+ * that processed this call, or {@link null} if no
+ * call screening service ran.
+ */
+ public CallFilteringCompletionInfo(boolean isBlocked, boolean isInContacts,
+ @Nullable CallScreeningService.CallResponse callResponse,
+ @Nullable ComponentName callScreeningComponent) {
+ mIsBlocked = isBlocked;
+ mIsInContacts = isInContacts;
+ mCallResponse = callResponse;
+ mCallScreeningComponent = callScreeningComponent;
+ }
+
+ /** @hide */
+ protected CallFilteringCompletionInfo(Parcel in) {
+ mIsBlocked = in.readByte() != 0;
+ mIsInContacts = in.readByte() != 0;
+ CallScreeningService.ParcelableCallResponse response
+ = in.readParcelable(CallScreeningService.class.getClassLoader());
+ mCallResponse = response == null ? null : response.toCallResponse();
+ mCallScreeningComponent = in.readParcelable(ComponentName.class.getClassLoader());
+ }
+
+ @NonNull
+ public static final Creator<CallFilteringCompletionInfo> CREATOR =
+ new Creator<CallFilteringCompletionInfo>() {
+ @Override
+ public CallFilteringCompletionInfo createFromParcel(Parcel in) {
+ return new CallFilteringCompletionInfo(in);
+ }
+
+ @Override
+ public CallFilteringCompletionInfo[] newArray(int size) {
+ return new CallFilteringCompletionInfo[size];
+ }
+ };
+
+ /**
+ * @return Whether any part of the call filtering process indicated that this call should be
+ * blocked.
+ */
+ public boolean isBlocked() {
+ return mIsBlocked;
+ }
+
+ /**
+ * @return Whether the caller is in the user's contacts.
+ */
+ public boolean isInContacts() {
+ return mIsInContacts;
+ }
+
+ /**
+ * @return The instance of {@link CallScreeningService.CallResponse} provided
+ * by the {@link CallScreeningService} that processed this
+ * call, or {@code null} if no call screening service ran.
+ */
+ public @Nullable CallScreeningService.CallResponse getCallResponse() {
+ return mCallResponse;
+ }
+
+ /**
+ * @return The component of the {@link CallScreeningService}
+ * that processed this call, or {@code null} if no call screening service ran.
+ */
+ public @Nullable ComponentName getCallScreeningComponent() {
+ return mCallScreeningComponent;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "CallFilteringCompletionInfo{" +
+ "mIsBlocked=" + mIsBlocked +
+ ", mIsInContacts=" + mIsInContacts +
+ ", mCallResponse=" + mCallResponse +
+ ", mCallScreeningPackageName='" + mCallScreeningComponent + '\'' +
+ '}';
+ }
+
+ /** @hide */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte((byte) (mIsBlocked ? 1 : 0));
+ dest.writeByte((byte) (mIsInContacts ? 1 : 0));
+ dest.writeParcelable(mCallResponse == null ? null : mCallResponse.toParcelable(), 0);
+ dest.writeParcelable(mCallScreeningComponent, 0);
+ }
+ }
+
+ /**
* Indicates that call filtering in Telecom is complete
*
* This method is called for a connection created via
@@ -3386,24 +3504,13 @@ public abstract class Connection extends Conferenceable {
* Telecom, including checking the blocked number db, per-contact settings, and custom call
* filtering apps.
*
- * @param isBlocked {@code true} if the call was blocked, {@code false} otherwise. If this is
- * {@code true}, {@link #onDisconnect()} will be called soon after
- * this is called.
- * @param isInContacts Indicates whether the caller is in the user's contacts list.
- * @param callScreeningResponse The response that was returned from the
- * {@link CallScreeningService} that handled this call. If no
- * response was received from a call screening service,
- * this will be {@code null}.
- * @param isResponseFromSystemDialer Whether {@code callScreeningResponse} was sent from the
- * system dialer. If {@code callScreeningResponse} is
- * {@code null}, this will be {@code false}.
+ * @param callFilteringCompletionInfo Info provided by Telecom on the results of call filtering.
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.READ_CONTACTS)
- public void onCallFilteringCompleted(boolean isBlocked, boolean isInContacts,
- @Nullable CallScreeningService.CallResponse callScreeningResponse,
- boolean isResponseFromSystemDialer) { }
+ public void onCallFilteringCompleted(
+ @NonNull CallFilteringCompletionInfo callFilteringCompletionInfo) { }
static String toLogSafePhoneNumber(String number) {
// For unknown number, log empty string.
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 966ece3a3ba2..c189b19c71af 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -758,19 +758,15 @@ public abstract class ConnectionService extends Service {
}
@Override
- public void onCallFilteringCompleted(String callId, boolean isBlocked, boolean isInContacts,
- CallScreeningService.ParcelableCallResponse callScreeningResponse,
- boolean isResponseFromSystemDialer,
+ public void onCallFilteringCompleted(String callId,
+ Connection.CallFilteringCompletionInfo completionInfo,
Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_CALL_FILTERING_COMPLETED);
try {
SomeArgs args = SomeArgs.obtain();
args.arg1 = callId;
- args.arg2 = isBlocked;
- args.arg3 = isInContacts;
- args.arg4 = callScreeningResponse;
- args.arg5 = isResponseFromSystemDialer;
- args.arg6 = Log.createSubsession();
+ args.arg2 = completionInfo;
+ args.arg3 = Log.createSubsession();
mHandler.obtainMessage(MSG_ON_CALL_FILTERING_COMPLETED, args).sendToTarget();
} finally {
Log.endSession();
@@ -1441,16 +1437,12 @@ public abstract class ConnectionService extends Service {
case MSG_ON_CALL_FILTERING_COMPLETED: {
SomeArgs args = (SomeArgs) msg.obj;
try {
- Log.continueSession((Session) args.arg6,
+ Log.continueSession((Session) args.arg3,
SESSION_HANDLER + SESSION_CALL_FILTERING_COMPLETED);
String callId = (String) args.arg1;
- boolean isBlocked = (boolean) args.arg2;
- boolean isInContacts = (boolean) args.arg3;
- CallScreeningService.ParcelableCallResponse callScreeningResponse =
- (CallScreeningService.ParcelableCallResponse) args.arg4;
- boolean isResponseFromSystemDialer = (boolean) args.arg5;
- onCallFilteringCompleted(callId, isBlocked, isInContacts,
- callScreeningResponse, isResponseFromSystemDialer);
+ Connection.CallFilteringCompletionInfo completionInfo =
+ (Connection.CallFilteringCompletionInfo) args.arg2;
+ onCallFilteringCompleted(callId, completionInfo);
} finally {
args.recycle();
Log.endSession();
@@ -2466,16 +2458,12 @@ public abstract class ConnectionService extends Service {
}
}
- private void onCallFilteringCompleted(String callId, boolean isBlocked, boolean isInContacts,
- CallScreeningService.ParcelableCallResponse callScreeningResponse,
- boolean isResponseFromSystemDialer) {
- Log.i(this, "onCallFilteringCompleted(%s, %b, %b, %s, %b)", callId,
- isBlocked, isInContacts, callScreeningResponse, isResponseFromSystemDialer);
+ private void onCallFilteringCompleted(String callId, Connection.CallFilteringCompletionInfo
+ callFilteringCompletionInfo) {
+ Log.i(this, "onCallFilteringCompleted(%s, %s)", callId, callFilteringCompletionInfo);
Connection connection = findConnectionForAction(callId, "onCallFilteringCompleted");
if (connection != null) {
- connection.onCallFilteringCompleted(isBlocked, isInContacts,
- callScreeningResponse == null ? null : callScreeningResponse.toCallResponse(),
- isResponseFromSystemDialer);
+ connection.onCallFilteringCompleted(callFilteringCompletionInfo);
}
}
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 6c6097ac71e5..7a6fddb6f029 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -1202,27 +1202,18 @@ public final class RemoteConnection {
/**
* Notifies this {@link RemoteConnection} that call filtering has completed, as well as
* the results of a contacts lookup for the remote party.
- * @param isBlocked Whether call filtering indicates that the call should be blocked
- * @param isInContacts Whether the remote party is in the user's contacts
- * @param callScreeningResponse The response that was returned from the
- * {@link CallScreeningService} that handled this call. If no
- * response was received from a call screening service,
- * this will be {@code null}.
- * @param isResponseFromSystemDialer Whether {@code callScreeningResponse} was sent from the
- * system dialer. If {@code callScreeningResponse} is
- * {@code null}, this will be {@code false}.
+ *
+ * @param completionInfo Info provided by Telecom on the results of call filtering.
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.READ_CONTACTS)
- public void onCallFilteringCompleted(boolean isBlocked, boolean isInContacts,
- @Nullable CallScreeningService.CallResponse callScreeningResponse,
- boolean isResponseFromSystemDialer) {
+ public void onCallFilteringCompleted(
+ @NonNull Connection.CallFilteringCompletionInfo completionInfo) {
Log.startSession("RC.oCFC", getActiveOwnerInfo());
try {
if (mConnected) {
- mConnectionService.onCallFilteringCompleted(mConnectionId, isBlocked, isInContacts,
- callScreeningResponse.toParcelable(), isResponseFromSystemDialer,
+ mConnectionService.onCallFilteringCompleted(mConnectionId, completionInfo,
null /*Session.Info*/);
}
} catch (RemoteException ignored) {
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 7599e189cc37..d72f8aa82ddb 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -20,7 +20,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.telecom.CallAudioState;
-import android.telecom.CallScreeningService;
+import android.telecom.Connection;
import android.telecom.ConnectionRequest;
import android.telecom.Logging.Session;
import android.telecom.PhoneAccountHandle;
@@ -119,9 +119,9 @@ oneway interface IConnectionService {
void sendCallEvent(String callId, String event, in Bundle extras, in Session.Info sessionInfo);
- void onCallFilteringCompleted(String callId, boolean isBlocked, boolean isInContacts,
- in CallScreeningService.ParcelableCallResponse callScreeningResponse,
- boolean isResponseFromSystemDialer, in Session.Info sessionInfo);
+ void onCallFilteringCompleted(String callId,
+ in Connection.CallFilteringCompletionInfo completionInfo,
+ in Session.Info sessionInfo);
void onExtrasChanged(String callId, in Bundle extras, in Session.Info sessionInfo);
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index c6757fba4d53..4ae11b8458cb 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -111,6 +111,7 @@ public class Annotation {
public @interface NetworkType {
}
+ // TODO(b/180542000): remove and replace references with @ApnSetting.ApnType
@IntDef(flag = true, prefix = {"TYPE_"}, value = {
ApnSetting.TYPE_DEFAULT,
ApnSetting.TYPE_MMS,
@@ -124,6 +125,7 @@ public class Annotation {
ApnSetting.TYPE_EMERGENCY,
ApnSetting.TYPE_MCX,
ApnSetting.TYPE_XCAP,
+ // ApnSetting.TYPE_ENTERPRISE
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApnType {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 8c68d856d896..3d43d031868d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -5321,7 +5321,7 @@ public class CarrierConfigManager {
sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_ORIGINATOR_STRING_ARRAY,
new String[0]);
sDefaults.putStringArray(KEY_APN_PRIORITY_STRING_ARRAY, new String[] {
- "default:0", "mms:2", "supl:2", "dun:2", "hipri:3", "fota:2",
+ "default:0", "enterprise:1", "mms:2", "supl:2", "dun:2", "hipri:3", "fota:2",
"ims:2", "cbs:2", "ia:2", "emergency:2", "mcx:3", "xcap:3"
});
sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]);
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index 99a77ae5d133..c8ed82cd2a3f 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -917,6 +917,10 @@ public final class DataFailCause {
public static final int HANDOFF_PREFERENCE_CHANGED = 0x8CB;
/** Data call fail due to the slice not being allowed for the data call. */
public static final int SLICE_REJECTED = 0x8CC;
+ /** No matching rule available for the request, and match-all rule is not allowed for it. */
+ public static final int MATCH_ALL_RULE_NOT_ALLOWED = 0x8CD;
+ /** If connection failed for all matching URSP rules. */
+ public static final int ALL_MATCHING_RULES_FAILED = 0x8CE;
//IKE error notifications message as specified in 3GPP TS 24.302 (Section 8.1.2.2).
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 6c013df66840..4926687f6724 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2649,6 +2649,37 @@ public final class SmsManager {
*/
public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl,
Bundle configOverrides, PendingIntent sentIntent) {
+ sendMultimediaMessage(context, contentUri, locationUrl, configOverrides, sentIntent,
+ 0L /* messageId */);
+ }
+
+ /**
+ * Send an MMS message
+ *
+ * Same as {@link #sendMultimediaMessage(Context context, Uri contentUri, String locationUrl,
+ * Bundle configOverrides, PendingIntent sentIntent)}, but adds an optional messageId.
+ * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
+ * manager on a multi-SIM device, this operation may fail sending the MMS message because no
+ * suitable default subscription could be found. In this case, if {@code sentIntent} is
+ * non-null, then the {@link PendingIntent} will be sent with an error code
+ * {@code RESULT_NO_DEFAULT_SMS_APP}. See {@link #getDefault()} for more information on the
+ * conditions where this operation may fail.
+ * </p>
+ *
+ * @param context application context
+ * @param contentUri the content Uri from which the message pdu will be read
+ * @param locationUrl the optional location url where message should be sent to
+ * @param configOverrides the carrier-specific messaging configuration values to override for
+ * sending the message.
+ * @param sentIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is successfully sent, or failed
+ * @param messageId an id that uniquely identifies the message requested to be sent.
+ * Used for logging and diagnostics purposes. The id may be 0.
+ * @throws IllegalArgumentException if contentUri is empty
+ */
+ public void sendMultimediaMessage(@NonNull Context context, @NonNull Uri contentUri,
+ @Nullable String locationUrl, @Nullable Bundle configOverrides,
+ @Nullable PendingIntent sentIntent, long messageId) {
if (contentUri == null) {
throw new IllegalArgumentException("Uri contentUri null");
}
@@ -2658,7 +2689,7 @@ public final class SmsManager {
@Override
public void onSuccess(int subId) {
m.sendMultimediaMessage(subId, contentUri, locationUrl, configOverrides,
- sentIntent, 0L /* messageId */);
+ sentIntent, messageId);
}
@Override
@@ -2692,6 +2723,39 @@ public final class SmsManager {
*/
public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri,
Bundle configOverrides, PendingIntent downloadedIntent) {
+ downloadMultimediaMessage(context, locationUrl, contentUri, configOverrides,
+ downloadedIntent, 0L /* messageId */);
+ }
+
+ /**
+ * Download an MMS message from carrier by a given location URL
+ *
+ * Same as {@link #downloadMultimediaMessage(Context context, String locationUrl,
+ * Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent)},
+ * but adds an optional messageId.
+ * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
+ * manager on a multi-SIM device, this operation may fail downloading the MMS message because no
+ * suitable default subscription could be found. In this case, if {@code downloadedIntent} is
+ * non-null, then the {@link PendingIntent} will be sent with an error code
+ * {@code RESULT_NO_DEFAULT_SMS_APP}. See {@link #getDefault()} for more information on the
+ * conditions where this operation may fail.
+ * </p>
+ *
+ * @param context application context
+ * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained
+ * from the MMS WAP push notification
+ * @param contentUri the content uri to which the downloaded pdu will be written
+ * @param configOverrides the carrier-specific messaging configuration values to override for
+ * downloading the message.
+ * @param downloadedIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is downloaded, or the download is failed
+ * @param messageId an id that uniquely identifies the message requested to be downloaded.
+ * Used for logging and diagnostics purposes. The id may be 0.
+ * @throws IllegalArgumentException if locationUrl or contentUri is empty
+ */
+ public void downloadMultimediaMessage(@NonNull Context context, @NonNull String locationUrl,
+ @NonNull Uri contentUri, @Nullable Bundle configOverrides,
+ @Nullable PendingIntent downloadedIntent, long messageId) {
if (TextUtils.isEmpty(locationUrl)) {
throw new IllegalArgumentException("Empty MMS location URL");
}
@@ -2704,7 +2768,7 @@ public final class SmsManager {
@Override
public void onSuccess(int subId) {
m.downloadMultimediaMessage(subId, locationUrl, contentUri, configOverrides,
- downloadedIntent, 0L /* messageId */);
+ downloadedIntent, messageId);
}
@Override
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index d58fa912dce2..b503733f8de9 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -28,8 +28,6 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.provider.Telephony;
import android.provider.Telephony.Carriers;
-import android.telephony.Annotation;
-import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.NetworkType;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
@@ -116,6 +114,31 @@ public class ApnSetting implements Parcelable {
public static final int TYPE_MCX = ApnTypes.MCX;
/** APN type for XCAP. */
public static final int TYPE_XCAP = ApnTypes.XCAP;
+ /**
+ * APN type for ENTERPRISE.
+ * @hide
+ */
+ public static final int TYPE_ENTERPRISE = TYPE_XCAP << 1;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = {"TYPE_"}, value = {
+ TYPE_DEFAULT,
+ TYPE_MMS,
+ TYPE_SUPL,
+ TYPE_DUN,
+ TYPE_HIPRI,
+ TYPE_FOTA,
+ TYPE_IMS,
+ TYPE_CBS,
+ TYPE_IA,
+ TYPE_EMERGENCY,
+ TYPE_MCX,
+ TYPE_XCAP,
+ TYPE_ENTERPRISE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ApnType {
+ }
// Possible values for authentication types.
/** No authentication type. */
@@ -151,6 +174,7 @@ public class ApnSetting implements Parcelable {
TYPE_MMS_STRING,
TYPE_SUPL_STRING,
TYPE_XCAP_STRING,
+ TYPE_ENTERPRISE_STRING,
}, prefix = "TYPE_", suffix = "_STRING")
@Retention(RetentionPolicy.SOURCE)
public @interface ApnTypeString {}
@@ -291,6 +315,12 @@ public class ApnSetting implements Parcelable {
@SystemApi
public static final String TYPE_XCAP_STRING = "xcap";
+ /**
+ * APN type for ENTERPRISE traffic.
+ * @hide
+ */
+ public static final String TYPE_ENTERPRISE_STRING = "enterprise";
+
/** @hide */
@IntDef(prefix = { "AUTH_TYPE_" }, value = {
@@ -370,6 +400,7 @@ public class ApnSetting implements Parcelable {
APN_TYPE_STRING_MAP.put(TYPE_EMERGENCY_STRING, TYPE_EMERGENCY);
APN_TYPE_STRING_MAP.put(TYPE_MCX_STRING, TYPE_MCX);
APN_TYPE_STRING_MAP.put(TYPE_XCAP_STRING, TYPE_XCAP);
+ APN_TYPE_STRING_MAP.put(TYPE_ENTERPRISE_STRING, TYPE_ENTERPRISE);
APN_TYPE_INT_MAP = new ArrayMap<>();
APN_TYPE_INT_MAP.put(TYPE_DEFAULT, TYPE_DEFAULT_STRING);
@@ -384,6 +415,7 @@ public class ApnSetting implements Parcelable {
APN_TYPE_INT_MAP.put(TYPE_EMERGENCY, TYPE_EMERGENCY_STRING);
APN_TYPE_INT_MAP.put(TYPE_MCX, TYPE_MCX_STRING);
APN_TYPE_INT_MAP.put(TYPE_XCAP, TYPE_XCAP_STRING);
+ APN_TYPE_INT_MAP.put(TYPE_ENTERPRISE, TYPE_ENTERPRISE_STRING);
PROTOCOL_STRING_MAP = new ArrayMap<>();
PROTOCOL_STRING_MAP.put("IP", PROTOCOL_IP);
@@ -1490,7 +1522,7 @@ public class ApnSetting implements Parcelable {
* @hide
*/
@SystemApi
- public static @NonNull @ApnTypeString String getApnTypeString(@Annotation.ApnType int apnType) {
+ public static @NonNull @ApnTypeString String getApnTypeString(@ApnType int apnType) {
if (apnType == TYPE_ALL) {
return "*";
}
@@ -1503,7 +1535,7 @@ public class ApnSetting implements Parcelable {
* when provided with an invalid int for compatibility purposes.
* @hide
*/
- public static @NonNull String getApnTypeStringInternal(@Annotation.ApnType int apnType) {
+ public static @NonNull String getApnTypeStringInternal(@ApnType int apnType) {
String result = getApnTypeString(apnType);
return TextUtils.isEmpty(result) ? "Unknown" : result;
}
@@ -1517,7 +1549,7 @@ public class ApnSetting implements Parcelable {
* @hide
*/
@SystemApi
- public static @Annotation.ApnType int getApnTypeInt(@NonNull @ApnTypeString String apnType) {
+ public static @ApnType int getApnTypeInt(@NonNull @ApnTypeString String apnType) {
return APN_TYPE_STRING_MAP.getOrDefault(apnType.toLowerCase(), 0);
}
@@ -2162,7 +2194,7 @@ public class ApnSetting implements Parcelable {
public ApnSetting build() {
if ((mApnTypeBitmask & (TYPE_DEFAULT | TYPE_MMS | TYPE_SUPL | TYPE_DUN | TYPE_HIPRI
| TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX
- | TYPE_XCAP)) == 0
+ | TYPE_XCAP | TYPE_ENTERPRISE)) == 0
|| TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) {
return null;
}
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index bd4bf0740ca1..a76422977cb6 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -138,6 +138,7 @@ public final class DataCallResponse implements Parcelable {
private final Qos mDefaultQos;
private final List<QosBearerSession> mQosBearerSessions;
private final SliceInfo mSliceInfo;
+ private final List<TrafficDescriptor> mTrafficDescriptors;
/**
* @param cause Data call fail cause. {@link DataFailCause#NONE} indicates no error.
@@ -189,6 +190,7 @@ public final class DataCallResponse implements Parcelable {
mDefaultQos = null;
mQosBearerSessions = new ArrayList<>();
mSliceInfo = null;
+ mTrafficDescriptors = new ArrayList<>();
}
private DataCallResponse(@DataFailureCause int cause, long suggestedRetryTime, int id,
@@ -198,7 +200,7 @@ public final class DataCallResponse implements Parcelable {
@Nullable List<InetAddress> pcscfAddresses, int mtu, int mtuV4, int mtuV6,
@HandoverFailureMode int handoverFailureMode, int pduSessionId,
@Nullable Qos defaultQos, @Nullable List<QosBearerSession> qosBearerSessions,
- @Nullable SliceInfo sliceInfo) {
+ @Nullable SliceInfo sliceInfo, @Nullable List<TrafficDescriptor> trafficDescriptors) {
mCause = cause;
mSuggestedRetryTime = suggestedRetryTime;
mId = id;
@@ -219,8 +221,11 @@ public final class DataCallResponse implements Parcelable {
mHandoverFailureMode = handoverFailureMode;
mPduSessionId = pduSessionId;
mDefaultQos = defaultQos;
- mQosBearerSessions = qosBearerSessions;
+ mQosBearerSessions = (qosBearerSessions == null)
+ ? new ArrayList<>() : new ArrayList<>(qosBearerSessions);
mSliceInfo = sliceInfo;
+ mTrafficDescriptors = (trafficDescriptors == null)
+ ? new ArrayList<>() : new ArrayList<>(trafficDescriptors);
}
/** @hide */
@@ -249,6 +254,8 @@ public final class DataCallResponse implements Parcelable {
mQosBearerSessions = new ArrayList<>();
source.readList(mQosBearerSessions, QosBearerSession.class.getClassLoader());
mSliceInfo = source.readParcelable(SliceInfo.class.getClassLoader());
+ mTrafficDescriptors = new ArrayList<>();
+ source.readList(mTrafficDescriptors, TrafficDescriptor.class.getClassLoader());
}
/**
@@ -381,7 +388,6 @@ public final class DataCallResponse implements Parcelable {
*
* @hide
*/
-
@Nullable
public Qos getDefaultQos() {
return mDefaultQos;
@@ -406,6 +412,14 @@ public final class DataCallResponse implements Parcelable {
return mSliceInfo;
}
+ /**
+ * @return The traffic descriptors related to this data connection.
+ */
+ @NonNull
+ public List<TrafficDescriptor> getTrafficDescriptors() {
+ return mTrafficDescriptors;
+ }
+
@NonNull
@Override
public String toString() {
@@ -429,6 +443,7 @@ public final class DataCallResponse implements Parcelable {
.append(" defaultQos=").append(mDefaultQos)
.append(" qosBearerSessions=").append(mQosBearerSessions)
.append(" sliceInfo=").append(mSliceInfo)
+ .append(" trafficDescriptors=").append(mTrafficDescriptors)
.append("}");
return sb.toString();
}
@@ -443,15 +458,22 @@ public final class DataCallResponse implements Parcelable {
DataCallResponse other = (DataCallResponse) o;
- final boolean isQosSame = (mDefaultQos == null || other.mDefaultQos == null) ?
- mDefaultQos == other.mDefaultQos :
- mDefaultQos.equals(other.mDefaultQos);
+ final boolean isQosSame = (mDefaultQos == null || other.mDefaultQos == null)
+ ? mDefaultQos == other.mDefaultQos
+ : mDefaultQos.equals(other.mDefaultQos);
- final boolean isQosBearerSessionsSame = (mQosBearerSessions == null || mQosBearerSessions == null) ?
- mQosBearerSessions == other.mQosBearerSessions :
- mQosBearerSessions.size() == other.mQosBearerSessions.size()
+ final boolean isQosBearerSessionsSame =
+ (mQosBearerSessions == null || other.mQosBearerSessions == null)
+ ? mQosBearerSessions == other.mQosBearerSessions
+ : mQosBearerSessions.size() == other.mQosBearerSessions.size()
&& mQosBearerSessions.containsAll(other.mQosBearerSessions);
+ final boolean isTrafficDescriptorsSame =
+ (mTrafficDescriptors == null || other.mTrafficDescriptors == null)
+ ? mTrafficDescriptors == other.mTrafficDescriptors
+ : mTrafficDescriptors.size() == other.mTrafficDescriptors.size()
+ && mTrafficDescriptors.containsAll(other.mTrafficDescriptors);
+
return mCause == other.mCause
&& mSuggestedRetryTime == other.mSuggestedRetryTime
&& mId == other.mId
@@ -473,7 +495,8 @@ public final class DataCallResponse implements Parcelable {
&& mPduSessionId == other.mPduSessionId
&& isQosSame
&& isQosBearerSessionsSame
- && Objects.equals(mSliceInfo, other.mSliceInfo);
+ && Objects.equals(mSliceInfo, other.mSliceInfo)
+ && isTrafficDescriptorsSame;
}
@Override
@@ -481,7 +504,7 @@ public final class DataCallResponse implements Parcelable {
return Objects.hash(mCause, mSuggestedRetryTime, mId, mLinkStatus, mProtocolType,
mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses, mPcscfAddresses,
mMtu, mMtuV4, mMtuV6, mHandoverFailureMode, mPduSessionId, mDefaultQos,
- mQosBearerSessions, mSliceInfo);
+ mQosBearerSessions, mSliceInfo, mTrafficDescriptors);
}
@Override
@@ -517,6 +540,7 @@ public final class DataCallResponse implements Parcelable {
}
dest.writeList(mQosBearerSessions);
dest.writeParcelable(mSliceInfo, flags);
+ dest.writeList(mTrafficDescriptors);
}
public static final @android.annotation.NonNull Parcelable.Creator<DataCallResponse> CREATOR =
@@ -602,6 +626,8 @@ public final class DataCallResponse implements Parcelable {
private SliceInfo mSliceInfo;
+ private List<TrafficDescriptor> mTrafficDescriptors = new ArrayList<>();
+
/**
* Default constructor for Builder.
*/
@@ -841,6 +867,24 @@ public final class DataCallResponse implements Parcelable {
}
/**
+ * The traffic descriptors for this data connection, as defined in 3GPP TS 24.526
+ * Section 5.2. They are used for URSP traffic matching as described in 3GPP TS 24.526
+ * Section 4.2.2. They includes an optional DNN, which, if present, must be used for traffic
+ * matching; it does not specify the end point to be used for the data call. The end point
+ * is specified by {@link DataProfile}, which must be used as the end point if one is not
+ * specified through URSP rules.
+ *
+ * @param trafficDescriptors the traffic descriptors for the data call.
+ *
+ * @return The same instance of the builder.
+ */
+ public @NonNull Builder setTrafficDescriptors(
+ @NonNull List<TrafficDescriptor> trafficDescriptors) {
+ mTrafficDescriptors = trafficDescriptors;
+ return this;
+ }
+
+ /**
* Build the DataCallResponse.
*
* @return the DataCallResponse object.
@@ -849,7 +893,7 @@ public final class DataCallResponse implements Parcelable {
return new DataCallResponse(mCause, mSuggestedRetryTime, mId, mLinkStatus,
mProtocolType, mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses,
mPcscfAddresses, mMtu, mMtuV4, mMtuV6, mHandoverFailureMode, mPduSessionId,
- mDefaultQos, mQosBearerSessions, mSliceInfo);
+ mDefaultQos, mQosBearerSessions, mSliceInfo, mTrafficDescriptors);
}
}
}
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 484c318c1ac0..f5f29c65b7cd 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -200,6 +200,17 @@ public abstract class DataService extends Service {
* handover is occurring from EPDG to 5G. If the slice passed is rejected, then
* {@link DataCallResponse#getCause()} is
* {@link android.telephony.DataFailCause#SLICE_REJECTED}.
+ * @param trafficDescriptor {@link TrafficDescriptor} for which data connection needs to be
+ * established. It is used for URSP traffic matching as described in 3GPP TS 24.526
+ * Section 4.2.2. It includes an optional DNN which, if present, must be used for
+ * traffic matching; it does not specify the end point to be used for the data call.
+ * @param matchAllRuleAllowed Indicates if using default match-all URSP rule for this
+ * request is allowed. If false, this request must not use the match-all URSP rule
+ * and if a non-match-all rule is not found (or if URSP rules are not available) then
+ * {@link DataCallResponse#getCause()} is
+ * {@link android.telephony.DataFailCause#MATCH_ALL_RULE_NOT_ALLOWED}. This is needed
+ * as some requests need to have a hard failure if the intention cannot be met,
+ * for example, a zero-rating slice.
* @param callback The result callback for this request.
*/
public void setupDataCall(int accessNetworkType, @NonNull DataProfile dataProfile,
@@ -207,6 +218,7 @@ public abstract class DataService extends Service {
@SetupDataReason int reason,
@Nullable LinkProperties linkProperties,
@IntRange(from = 0, to = 15) int pduSessionId, @Nullable SliceInfo sliceInfo,
+ @Nullable TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed,
@NonNull DataServiceCallback callback) {
/* Call the old version since the new version isn't supported */
setupDataCall(accessNetworkType, dataProfile, isRoaming, allowRoaming, reason,
@@ -403,10 +415,13 @@ public abstract class DataService extends Service {
public final LinkProperties linkProperties;
public final int pduSessionId;
public final SliceInfo sliceInfo;
+ public final TrafficDescriptor trafficDescriptor;
+ public final boolean matchAllRuleAllowed;
public final IDataServiceCallback callback;
SetupDataCallRequest(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
- boolean allowRoaming, int reason, LinkProperties linkProperties,
- int pduSessionId, SliceInfo sliceInfo, IDataServiceCallback callback) {
+ boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId,
+ SliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
+ boolean matchAllRuleAllowed, IDataServiceCallback callback) {
this.accessNetworkType = accessNetworkType;
this.dataProfile = dataProfile;
this.isRoaming = isRoaming;
@@ -415,6 +430,8 @@ public abstract class DataService extends Service {
this.reason = reason;
this.pduSessionId = pduSessionId;
this.sliceInfo = sliceInfo;
+ this.trafficDescriptor = trafficDescriptor;
+ this.matchAllRuleAllowed = matchAllRuleAllowed;
this.callback = callback;
}
}
@@ -525,7 +542,8 @@ public abstract class DataService extends Service {
setupDataCallRequest.dataProfile, setupDataCallRequest.isRoaming,
setupDataCallRequest.allowRoaming, setupDataCallRequest.reason,
setupDataCallRequest.linkProperties, setupDataCallRequest.pduSessionId,
- setupDataCallRequest.sliceInfo,
+ setupDataCallRequest.sliceInfo, setupDataCallRequest.trafficDescriptor,
+ setupDataCallRequest.matchAllRuleAllowed,
(setupDataCallRequest.callback != null)
? new DataServiceCallback(setupDataCallRequest.callback)
: null);
@@ -690,11 +708,12 @@ public abstract class DataService extends Service {
public void setupDataCall(int slotIndex, int accessNetworkType, DataProfile dataProfile,
boolean isRoaming, boolean allowRoaming, int reason,
LinkProperties linkProperties, int pduSessionId, SliceInfo sliceInfo,
+ TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed,
IDataServiceCallback callback) {
mHandler.obtainMessage(DATA_SERVICE_REQUEST_SETUP_DATA_CALL, slotIndex, 0,
new SetupDataCallRequest(accessNetworkType, dataProfile, isRoaming,
allowRoaming, reason, linkProperties, pduSessionId, sliceInfo,
- callback))
+ trafficDescriptor, matchAllRuleAllowed, callback))
.sendToTarget();
}
diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl
index e0b9a1a9bb5a..81f5fd3b69a9 100644
--- a/telephony/java/android/telephony/data/IDataService.aidl
+++ b/telephony/java/android/telephony/data/IDataService.aidl
@@ -20,6 +20,7 @@ import android.net.LinkProperties;
import android.telephony.data.DataProfile;
import android.telephony.data.IDataServiceCallback;
import android.telephony.data.SliceInfo;
+import android.telephony.data.TrafficDescriptor;
/**
* {@hide}
@@ -30,7 +31,9 @@ oneway interface IDataService
void removeDataServiceProvider(int slotId);
void setupDataCall(int slotId, int accessNetwork, in DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, in LinkProperties linkProperties,
- int pduSessionId, in SliceInfo sliceInfo, IDataServiceCallback callback);
+ int pduSessionId, in SliceInfo sliceInfo,
+ in TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed,
+ IDataServiceCallback callback);
void deactivateDataCall(int slotId, int cid, int reason, IDataServiceCallback callback);
void setInitialAttachApn(int slotId, in DataProfile dataProfile, boolean isRoaming,
IDataServiceCallback callback);
diff --git a/telephony/java/android/telephony/data/TrafficDescriptor.aidl b/telephony/java/android/telephony/data/TrafficDescriptor.aidl
new file mode 100644
index 000000000000..a9c7604a91b6
--- /dev/null
+++ b/telephony/java/android/telephony/data/TrafficDescriptor.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** @hide */
+package android.telephony.data;
+
+parcelable TrafficDescriptor;
diff --git a/telephony/java/android/telephony/data/TrafficDescriptor.java b/telephony/java/android/telephony/data/TrafficDescriptor.java
new file mode 100644
index 000000000000..480379d641b6
--- /dev/null
+++ b/telephony/java/android/telephony/data/TrafficDescriptor.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * A traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2. It is used for URSP traffic
+ * matching as described in 3GPP TS 24.526 Section 4.2.2. It includes an optional DNN, which,
+ * if present, must be used for traffic matching; it does not specify the end point to be used for
+ * the data call.
+ * @hide
+ */
+@SystemApi
+public final class TrafficDescriptor implements Parcelable {
+ private final String mDnn;
+ private final String mOsAppId;
+
+ private TrafficDescriptor(@NonNull Parcel in) {
+ mDnn = in.readString();
+ mOsAppId = in.readString();
+ }
+
+ /**
+ * Create a traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2
+ * @param dnn optional DNN, which must be used for traffic matching, if present
+ * @param osAppId OsId + osAppId of the traffic descriptor
+ */
+ public TrafficDescriptor(@Nullable String dnn, @Nullable String osAppId) {
+ mDnn = dnn;
+ mOsAppId = osAppId;
+ }
+
+ /**
+ * DNN stands for Data Network Name and represents an APN as defined in 3GPP TS 23.003.
+ * @return the DNN of this traffic descriptor.
+ */
+ public @Nullable String getDnn() {
+ return mDnn;
+ }
+
+ /**
+ * OsAppId represents the OsId + OsAppId as defined in 3GPP TS 24.526 Section 5.2.
+ * @return the OS App ID of this traffic descriptor.
+ */
+ public @Nullable String getOsAppId() {
+ return mOsAppId;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull @Override
+ public String toString() {
+ return "TrafficDescriptor={mDnn=" + mDnn + ", mOsAppId=" + mOsAppId + "}";
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mDnn);
+ dest.writeString(mOsAppId);
+ }
+
+ public static final @NonNull Parcelable.Creator<TrafficDescriptor> CREATOR =
+ new Parcelable.Creator<TrafficDescriptor>() {
+ @Override
+ public @NonNull TrafficDescriptor createFromParcel(@NonNull Parcel source) {
+ return new TrafficDescriptor(source);
+ }
+
+ @Override
+ public @NonNull TrafficDescriptor[] newArray(int size) {
+ return new TrafficDescriptor[size];
+ }
+ };
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ TrafficDescriptor that = (TrafficDescriptor) o;
+ return Objects.equals(mDnn, that.mDnn) && Objects.equals(mOsAppId, that.mOsAppId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDnn, mOsAppId);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 5c255243f52b..0048d53f9172 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2055,6 +2055,11 @@ interface ITelephony {
int setImsProvisioningString(int subId, int key, String value);
/**
+ * Start emergency callback mode for testing.
+ */
+ void startEmergencyCallbackMode();
+
+ /**
* Update Emergency Number List for Test Mode.
*/
void updateEmergencyNumberListTestMode(int action, in EmergencyNumber num);
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 151187c5071f..3a99f0e010c6 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -126,6 +126,7 @@ public class PhoneConstants {
* connections.<br/>
* APN_TYPE_ALL is a special type to indicate that this APN entry can
* service all data connections.
+ * TODO: remove these and use the reference to ApnSetting.TYPE_XXX_STRING instead
*/
public static final String APN_TYPE_ALL = ApnSetting.TYPE_ALL_STRING;
/** APN type for default data traffic */
@@ -153,20 +154,8 @@ public class PhoneConstants {
public static final String APN_TYPE_MCX = ApnSetting.TYPE_MCX_STRING;
/** APN type for XCAP */
public static final String APN_TYPE_XCAP = ApnSetting.TYPE_XCAP_STRING;
- /** Array of all APN types */
- public static final String[] APN_TYPES = {APN_TYPE_DEFAULT,
- APN_TYPE_MMS,
- APN_TYPE_SUPL,
- APN_TYPE_DUN,
- APN_TYPE_HIPRI,
- APN_TYPE_FOTA,
- APN_TYPE_IMS,
- APN_TYPE_CBS,
- APN_TYPE_IA,
- APN_TYPE_EMERGENCY,
- APN_TYPE_MCX,
- APN_TYPE_XCAP,
- };
+ // /** APN type for enterprise */
+ // public static final String APN_TYPE_ENTERPRISE = ApnSetting.TYPE_ENTERPRISE_STRING;
public static final int RIL_CARD_MAX_APPS = 8;
diff --git a/test-base/Android.bp b/test-base/Android.bp
index 0b7a3981a403..9bd639b63ae0 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -49,6 +49,12 @@ java_sdk_library {
compile_dex: true,
default_to_stubs: true,
+
+ // Additional hiddenapi annotations are provided in a separate module.
+ // TODO(b/180295980) - investigate whether this can be removed
+ hiddenapi_additional_annotations: [
+ "android.test.base-hiddenapi-annotations",
+ ],
}
// Build the android.test.base_static library
@@ -91,8 +97,9 @@ java_library_static {
// ===============================================
// This contains the android.test classes from android.test.base plus
// the com.android.internal.util.Predicate[s] classes. This is only
-// intended for inclusion in android.test.legacy and must not be used
-// elsewhere.
+// intended for inclusion in android.test.legacy and in
+// android.test.base-hiddenapi-annotations to avoid a dependency cycle and must
+// not be used elsewhere.
java_library_static {
name: "android.test.base-minus-junit",
diff --git a/test-base/hiddenapi/Android.bp b/test-base/hiddenapi/Android.bp
index d4f52d0fc6cd..1466590ef311 100644
--- a/test-base/hiddenapi/Android.bp
+++ b/test-base/hiddenapi/Android.bp
@@ -14,11 +14,6 @@
// limitations under the License.
//
-// Provided solely to contribute information about which hidden parts of the android.test.base
-// library are used by apps. The source files are stubs of the actual files in ../src which use the
-// UnsupportedAppUsage annotation to tag those methods that are accessible via the hiddenapi.
-// Relies on the convention that modules with name <x>-hiddenapi provide hiddenapi information for
-// module <x> that is on the bootclasspath.
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
@@ -28,14 +23,20 @@ package {
default_applicable_licenses: ["frameworks_base_license"],
}
+// Provided solely to contribute information about which hidden parts of the android.test.base
+// library are used by apps. The source files are stubs of the actual files in ../src which use the
+// UnsupportedAppUsage annotation to tag those methods that are accessible via the hiddenapi.
java_library {
- name: "android.test.base-hiddenapi",
+ name: "android.test.base-hiddenapi-annotations",
compile_dex: true,
srcs: ["src/**/*.java"],
libs: [
- "android.test.base",
+ // Use this instead of `android.test.base` to avoid a dependency cycle
+ // as `android.test.base` depends on this.
+ "android.test.base-minus-junit",
+ "junit",
"unsupportedappusage",
],
}
diff --git a/tests/BatteryStatsPerfTest/Android.bp b/tests/BatteryStatsPerfTest/Android.bp
index 58ccec705419..5233a5b8654e 100644
--- a/tests/BatteryStatsPerfTest/Android.bp
+++ b/tests/BatteryStatsPerfTest/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test {
name: "BatteryStatsPerfTests",
srcs: ["src/**/*.java"],
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index c5447c1ccf71..7d29cdd2b5c5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -17,382 +17,91 @@
package com.android.server.wm.flicker
import android.platform.helpers.IAppHelper
-import com.android.server.wm.flicker.dsl.EventLogAssertionBuilder
-import com.android.server.wm.flicker.dsl.EventLogAssertionBuilderLegacy
-import com.android.server.wm.flicker.dsl.LayersAssertionBuilder
-import com.android.server.wm.flicker.dsl.LayersAssertionBuilderLegacy
-import com.android.server.wm.flicker.dsl.WmAssertionBuilder
-import com.android.server.wm.flicker.dsl.WmAssertionBuilderLegacy
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_LAYER_NAME
-import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_WINDOW_NAME
-import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_LAYER_NAME
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_WINDOW_NAME
const val APP_PAIR_SPLIT_DIVIDER = "AppPairSplitDivider"
const val DOCKED_STACK_DIVIDER = "DockedStackDivider"
const val WALLPAPER_TITLE = "Wallpaper"
-@JvmOverloads
-fun WmAssertionBuilder.statusBarWindowIsAlwaysVisible(bugId: Int = 0) {
- all("statusBarWindowIsAlwaysVisible", bugId) {
+fun FlickerTestParameter.statusBarWindowIsAlwaysVisible() {
+ assertWm {
this.showsAboveAppWindow(NAV_BAR_LAYER_NAME)
}
}
-@JvmOverloads
-fun WmAssertionBuilder.navBarWindowIsAlwaysVisible(bugId: Int = 0) {
- all("navBarWindowIsAlwaysVisible", bugId) {
+fun FlickerTestParameter.navBarWindowIsAlwaysVisible() {
+ assertWm {
this.showsAboveAppWindow(NAV_BAR_LAYER_NAME)
}
}
-fun WmAssertionBuilder.visibleWindowsShownMoreThanOneConsecutiveEntry(
- ignoreWindows: List<String> = emptyList(),
- bugId: Int = 0
-) {
- all("visibleWindowsShownMoreThanOneConsecutiveEntry", bugId) {
- this.visibleWindowsShownMoreThanOneConsecutiveEntry(ignoreWindows)
- }
-}
-
-fun WmAssertionBuilder.launcherReplacesAppWindowAsTopWindow(testApp: IAppHelper, bugId: Int = 0) {
- all("launcherReplacesAppWindowAsTopWindow", bugId) {
- this.showsAppWindowOnTop(testApp.getPackage())
- .then()
- .showsAppWindowOnTop("Launcher")
- }
-}
-
-fun WmAssertionBuilder.wallpaperWindowBecomesVisible(bugId: Int = 0) {
- all("wallpaperWindowBecomesVisible", bugId) {
- this.hidesBelowAppWindow(WALLPAPER_TITLE)
- .then()
- .showsBelowAppWindow(WALLPAPER_TITLE)
- }
-}
-
-fun WmAssertionBuilder.wallpaperWindowBecomesInvisible(bugId: Int = 0) {
- all("wallpaperWindowBecomesInvisible", bugId) {
- this.showsBelowAppWindow("Wallpaper")
- .then()
- .hidesBelowAppWindow("Wallpaper")
- }
-}
-
-fun WmAssertionBuilder.appWindowAlwaysVisibleOnTop(
- packageName: String,
- bugId: Int = 0
-) {
- all("appWindowAlwaysVisibleOnTop", bugId) {
- this.showsAppWindowOnTop(packageName)
- }
-}
-
-fun WmAssertionBuilder.appWindowBecomesVisible(appName: String, bugId: Int = 0) {
- all("appWindowBecomesVisible", bugId) {
- this.hidesAppWindow(appName)
- .then()
- .showsAppWindow(appName)
- }
-}
-
-fun WmAssertionBuilder.appWindowBecomesInVisible(appName: String, bugId: Int = 0) {
- all("appWindowBecomesInVisible", bugId) {
- this.showsAppWindow(appName)
- .then()
- .hidesAppWindow(appName)
- }
-}
-
-@JvmOverloads
-fun LayersAssertionBuilder.noUncoveredRegions(
- beginRotation: Int,
- endRotation: Int = beginRotation,
- allStates: Boolean = true,
- bugId: Int = 0
-) {
- val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
- val endingBounds = WindowUtils.getDisplayBounds(endRotation)
- if (allStates) {
- all("noUncoveredRegions", bugId) {
- if (startingBounds == endingBounds) {
- this.coversAtLeastRegion(startingBounds)
- } else {
- this.coversAtLeastRegion(startingBounds)
- .then()
- .coversAtLeastRegion(endingBounds)
- }
- }
- } else {
- start("noUncoveredRegions_StartingPos") {
- this.coversAtLeastRegion(startingBounds)
- }
- end("noUncoveredRegions_EndingPos") {
- this.coversAtLeastRegion(endingBounds)
- }
- }
-}
-
-@JvmOverloads
-fun LayersAssertionBuilder.navBarLayerIsAlwaysVisible(
- rotatesScreen: Boolean = false,
- bugId: Int = 0
-) {
- if (rotatesScreen) {
- all("navBarLayerIsAlwaysVisible", bugId) {
- this.showsLayer(NAV_BAR_LAYER_NAME)
- .then()
- .hidesLayer(NAV_BAR_LAYER_NAME)
- .then()
- .showsLayer(NAV_BAR_LAYER_NAME)
- }
- } else {
- all("navBarLayerIsAlwaysVisible", bugId) {
- this.showsLayer(NAV_BAR_LAYER_NAME)
- }
- }
-}
-
-@JvmOverloads
-fun LayersAssertionBuilder.statusBarLayerIsAlwaysVisible(
- rotatesScreen: Boolean = false,
- bugId: Int = 0
-) {
- if (rotatesScreen) {
- all("statusBarLayerIsAlwaysVisible", bugId) {
- this.showsLayer(STATUS_BAR_WINDOW_NAME)
- .then()
- hidesLayer(STATUS_BAR_WINDOW_NAME)
- .then()
- .showsLayer(STATUS_BAR_WINDOW_NAME)
- }
- } else {
- all("statusBarLayerIsAlwaysVisible", bugId) {
- this.showsLayer(STATUS_BAR_WINDOW_NAME)
- }
- }
-}
-
-@JvmOverloads
-fun LayersAssertionBuilder.navBarLayerRotatesAndScales(
- beginRotation: Int,
- endRotation: Int = beginRotation,
- bugId: Int = 0
-) {
- val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
- val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
-
- start("navBarLayerRotatesAndScales_StartingPos", bugId) {
- this.hasVisibleRegion(NAV_BAR_LAYER_NAME, startingPos)
- }
- end("navBarLayerRotatesAndScales_EndingPost", bugId) {
- this.hasVisibleRegion(NAV_BAR_LAYER_NAME, endingPos)
- }
-
- /*if (startingPos == endingPos) {
- all("navBarLayerRotatesAndScales", enabled = false, bugId = 167747321) {
- this.hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- }
- }*/
-}
-
-@JvmOverloads
-fun LayersAssertionBuilder.statusBarLayerRotatesScales(
- beginRotation: Int,
- endRotation: Int = beginRotation,
- bugId: Int = 0
-) {
- val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
- val endingPos = WindowUtils.getStatusBarPosition(endRotation)
-
- start("statusBarLayerRotatesScales_StartingPos", bugId) {
- this.hasVisibleRegion(STATUS_BAR_WINDOW_NAME, startingPos)
- }
- end("statusBarLayerRotatesScales_EndingPos", bugId) {
- this.hasVisibleRegion(STATUS_BAR_WINDOW_NAME, endingPos)
- }
-}
-
-fun LayersAssertionBuilder.visibleLayersShownMoreThanOneConsecutiveEntry(
- ignoreLayers: List<String> = emptyList(),
- bugId: Int = 0
-) {
- all("visibleLayersShownMoreThanOneConsecutiveEntry", bugId) {
- this.visibleLayersShownMoreThanOneConsecutiveEntry(ignoreLayers)
- }
-}
-
-fun LayersAssertionBuilder.appLayerReplacesWallpaperLayer(appName: String, bugId: Int = 0) {
- all("appLayerReplacesWallpaperLayer", bugId) {
- this.showsLayer("Wallpaper")
- .then()
- .replaceVisibleLayer("Wallpaper", appName)
- }
-}
-
-fun LayersAssertionBuilder.wallpaperLayerReplacesAppLayer(testApp: IAppHelper, bugId: Int = 0) {
- all("appLayerReplacesWallpaperLayer", bugId) {
- this.showsLayer(testApp.getPackage())
- .then()
- .replaceVisibleLayer(testApp.getPackage(), WALLPAPER_TITLE)
- }
-}
-
-fun LayersAssertionBuilder.layerAlwaysVisible(packageName: String, bugId: Int = 0) {
- all("layerAlwaysVisible", bugId) {
- this.showsLayer(packageName)
- }
-}
-
-fun LayersAssertionBuilder.layerBecomesVisible(packageName: String, bugId: Int = 0) {
- all("layerBecomesVisible", bugId) {
- this.hidesLayer(packageName)
- .then()
- .showsLayer(packageName)
- }
-}
-
-fun LayersAssertionBuilder.layerBecomesInvisible(packageName: String, bugId: Int = 0) {
- all("layerBecomesInvisible", bugId) {
- this.showsLayer(packageName)
- .then()
- .hidesLayer(packageName)
- }
-}
-
-fun EventLogAssertionBuilder.focusChanges(vararg windows: String, bugId: Int = 0) {
- all("focusChanges", bugId) {
- this.focusChanges(windows)
- }
-}
-
-fun EventLogAssertionBuilder.focusDoesNotChange(bugId: Int = 0) {
- all("focusDoesNotChange", bugId) {
- this.focusDoesNotChange()
- }
-}
-
@JvmOverloads
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun WmAssertionBuilderLegacy.statusBarWindowIsAlwaysVisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
+fun FlickerTestParameter.visibleWindowsShownMoreThanOneConsecutiveEntry(
+ ignoreWindows: List<String> = emptyList()
) {
- all("statusBarWindowIsAlwaysVisible", bugId, enabled) {
- this.showsAboveAppWindow(STATUS_BAR_WINDOW_NAME)
- }
-}
-
-@JvmOverloads
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun WmAssertionBuilderLegacy.navBarWindowIsAlwaysVisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("navBarWindowIsAlwaysVisible", bugId, enabled) {
- this.showsAboveAppWindow(NAV_BAR_WINDOW_NAME)
- }
-}
-
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun WmAssertionBuilderLegacy.visibleWindowsShownMoreThanOneConsecutiveEntry(
- ignoreWindows: List<String> = emptyList(),
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("visibleWindowsShownMoreThanOneConsecutiveEntry", bugId, enabled) {
+ assertWm {
this.visibleWindowsShownMoreThanOneConsecutiveEntry(ignoreWindows)
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun WmAssertionBuilderLegacy.launcherReplacesAppWindowAsTopWindow(
- testApp: IAppHelper,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("launcherReplacesAppWindowAsTopWindow", bugId, enabled) {
+fun FlickerTestParameter.launcherReplacesAppWindowAsTopWindow(testApp: IAppHelper) {
+ assertWm {
this.showsAppWindowOnTop(testApp.getPackage())
.then()
.showsAppWindowOnTop("Launcher")
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun WmAssertionBuilderLegacy.wallpaperWindowBecomesVisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("wallpaperWindowBecomesVisible", bugId, enabled) {
+fun FlickerTestParameter.wallpaperWindowBecomesVisible() {
+ assertWm {
this.hidesBelowAppWindow(WALLPAPER_TITLE)
.then()
.showsBelowAppWindow(WALLPAPER_TITLE)
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun WmAssertionBuilderLegacy.wallpaperWindowBecomesInvisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("wallpaperWindowBecomesInvisible", bugId, enabled) {
+fun FlickerTestParameter.wallpaperWindowBecomesInvisible() {
+ assertWm {
this.showsBelowAppWindow("Wallpaper")
.then()
.hidesBelowAppWindow("Wallpaper")
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun WmAssertionBuilderLegacy.appWindowAlwaysVisibleOnTop(
- packageName: String,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("appWindowAlwaysVisibleOnTop", bugId, enabled) {
+fun FlickerTestParameter.appWindowAlwaysVisibleOnTop(packageName: String) {
+ assertWm {
this.showsAppWindowOnTop(packageName)
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun WmAssertionBuilderLegacy.appWindowBecomesVisible(
- appName: String,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("appWindowBecomesVisible", bugId, enabled) {
+fun FlickerTestParameter.appWindowBecomesVisible(appName: String) {
+ assertWm {
this.hidesAppWindow(appName)
.then()
.showsAppWindow(appName)
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun WmAssertionBuilderLegacy.appWindowBecomesInVisible(
- appName: String,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("appWindowBecomesInVisible", bugId, enabled) {
+fun FlickerTestParameter.appWindowBecomesInVisible(appName: String) {
+ assertWm {
this.showsAppWindow(appName)
.then()
.hidesAppWindow(appName)
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
@JvmOverloads
-fun LayersAssertionBuilderLegacy.noUncoveredRegions(
+fun FlickerTestParameter.noUncoveredRegions(
beginRotation: Int,
endRotation: Int = beginRotation,
- allStates: Boolean = true,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
+ allStates: Boolean = true
) {
val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
val endingBounds = WindowUtils.getDisplayBounds(endRotation)
if (allStates) {
- all("noUncoveredRegions", bugId, enabled) {
+ assertLayers {
if (startingBounds == endingBounds) {
this.coversAtLeastRegion(startingBounds)
} else {
@@ -402,24 +111,19 @@ fun LayersAssertionBuilderLegacy.noUncoveredRegions(
}
}
} else {
- start("noUncoveredRegions_StartingPos") {
+ assertLayersStart {
this.coversAtLeastRegion(startingBounds)
}
- end("noUncoveredRegions_EndingPos") {
+ assertLayersEnd {
this.coversAtLeastRegion(endingBounds)
}
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
@JvmOverloads
-fun LayersAssertionBuilderLegacy.navBarLayerIsAlwaysVisible(
- rotatesScreen: Boolean = false,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
+fun FlickerTestParameter.navBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
if (rotatesScreen) {
- all("navBarLayerIsAlwaysVisible", bugId, enabled) {
+ assertLayers {
this.showsLayer(NAV_BAR_LAYER_NAME)
.then()
.hidesLayer(NAV_BAR_LAYER_NAME)
@@ -427,169 +131,116 @@ fun LayersAssertionBuilderLegacy.navBarLayerIsAlwaysVisible(
.showsLayer(NAV_BAR_LAYER_NAME)
}
} else {
- all("navBarLayerIsAlwaysVisible", bugId, enabled) {
+ assertLayers {
this.showsLayer(NAV_BAR_LAYER_NAME)
}
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
@JvmOverloads
-fun LayersAssertionBuilderLegacy.statusBarLayerIsAlwaysVisible(
- rotatesScreen: Boolean = false,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
+fun FlickerTestParameter.statusBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
if (rotatesScreen) {
- all("statusBarLayerIsAlwaysVisible", bugId, enabled) {
- this.showsLayer(STATUS_BAR_LAYER_NAME)
+ assertLayers {
+ this.showsLayer(STATUS_BAR_WINDOW_NAME)
.then()
- .hidesLayer(STATUS_BAR_LAYER_NAME)
+ hidesLayer(STATUS_BAR_WINDOW_NAME)
.then()
- .showsLayer(STATUS_BAR_LAYER_NAME)
+ .showsLayer(STATUS_BAR_WINDOW_NAME)
}
} else {
- all("statusBarLayerIsAlwaysVisible", bugId, enabled) {
- this.showsLayer(STATUS_BAR_LAYER_NAME)
+ assertLayers {
+ this.showsLayer(STATUS_BAR_WINDOW_NAME)
}
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
@JvmOverloads
-fun LayersAssertionBuilderLegacy.navBarLayerRotatesAndScales(
+fun FlickerTestParameter.navBarLayerRotatesAndScales(
beginRotation: Int,
- endRotation: Int = beginRotation,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
+ endRotation: Int = beginRotation
) {
val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
- start("navBarLayerRotatesAndScales_StartingPos", bugId, enabled) {
+ assertLayersStart {
this.hasVisibleRegion(NAV_BAR_LAYER_NAME, startingPos)
}
- end("navBarLayerRotatesAndScales_EndingPost", bugId, enabled) {
+ assertLayersEnd {
this.hasVisibleRegion(NAV_BAR_LAYER_NAME, endingPos)
}
-
- if (startingPos == endingPos) {
- all("navBarLayerRotatesAndScales", enabled = false, bugId = 167747321) {
- this.hasVisibleRegion(NAV_BAR_LAYER_NAME, startingPos)
- }
- }
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
@JvmOverloads
-fun LayersAssertionBuilderLegacy.statusBarLayerRotatesScales(
+fun FlickerTestParameter.statusBarLayerRotatesScales(
beginRotation: Int,
- endRotation: Int = beginRotation,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
+ endRotation: Int = beginRotation
) {
val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
val endingPos = WindowUtils.getStatusBarPosition(endRotation)
- start("statusBarLayerRotatesScales_StartingPos", bugId, enabled) {
- this.hasVisibleRegion(STATUS_BAR_LAYER_NAME, startingPos)
+ assertLayersStart {
+ this.hasVisibleRegion(STATUS_BAR_WINDOW_NAME, startingPos)
}
- end("statusBarLayerRotatesScales_EndingPos", bugId, enabled) {
- this.hasVisibleRegion(STATUS_BAR_LAYER_NAME, endingPos)
+ assertLayersEnd {
+ this.hasVisibleRegion(STATUS_BAR_WINDOW_NAME, endingPos)
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun LayersAssertionBuilderLegacy.visibleLayersShownMoreThanOneConsecutiveEntry(
- ignoreLayers: List<String> = kotlin.collections.emptyList(),
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
+@JvmOverloads
+fun FlickerTestParameter.visibleLayersShownMoreThanOneConsecutiveEntry(
+ ignoreLayers: List<String> = emptyList()
) {
- all("visibleLayersShownMoreThanOneConsecutiveEntry", bugId, enabled) {
+ assertLayers {
this.visibleLayersShownMoreThanOneConsecutiveEntry(ignoreLayers)
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun LayersAssertionBuilderLegacy.appLayerReplacesWallpaperLayer(
- appName: String,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("appLayerReplacesWallpaperLayer", bugId, enabled) {
+fun FlickerTestParameter.appLayerReplacesWallpaperLayer(appName: String) {
+ assertLayers {
this.showsLayer("Wallpaper")
.then()
.replaceVisibleLayer("Wallpaper", appName)
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun LayersAssertionBuilderLegacy.wallpaperLayerReplacesAppLayer(
- testApp: IAppHelper,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("appLayerReplacesWallpaperLayer", bugId, enabled) {
+fun FlickerTestParameter.wallpaperLayerReplacesAppLayer(testApp: IAppHelper) {
+ assertLayers {
this.showsLayer(testApp.getPackage())
.then()
.replaceVisibleLayer(testApp.getPackage(), WALLPAPER_TITLE)
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun LayersAssertionBuilderLegacy.layerAlwaysVisible(
- packageName: String,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("layerAlwaysVisible", bugId, enabled) {
+fun FlickerTestParameter.layerAlwaysVisible(packageName: String) {
+ assertLayers {
this.showsLayer(packageName)
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun LayersAssertionBuilderLegacy.layerBecomesVisible(
- packageName: String,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("layerBecomesVisible", bugId, enabled) {
+fun FlickerTestParameter.layerBecomesVisible(packageName: String) {
+ assertLayers {
this.hidesLayer(packageName)
.then()
.showsLayer(packageName)
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun LayersAssertionBuilderLegacy.layerBecomesInvisible(
- packageName: String,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("layerBecomesInvisible", bugId, enabled) {
+fun FlickerTestParameter.layerBecomesInvisible(packageName: String) {
+ assertLayers {
this.showsLayer(packageName)
.then()
.hidesLayer(packageName)
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun EventLogAssertionBuilderLegacy.focusChanges(
- vararg windows: String,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("focusChanges", bugId, enabled) {
+fun FlickerTestParameter.focusChanges(vararg windows: String) {
+ assertEventLog {
this.focusChanges(windows)
}
}
-@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
-fun EventLogAssertionBuilderLegacy.focusDoesNotChange(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("focusDoesNotChange", bugId, enabled) {
+fun FlickerTestParameter.focusDoesNotChange() {
+ assertEventLog {
this.focusDoesNotChange()
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index c507841ffb71..fbf18d45afd8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -16,11 +16,17 @@
package com.android.server.wm.flicker.close
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
-import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
@@ -35,12 +41,12 @@ import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.helpers.buildTestTag
-import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
+import org.junit.Assume
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -51,86 +57,119 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseAppBackButtonTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
+class CloseAppBackButtonTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = SimpleAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ this.setRotation(testSpec.config.startRotation)
+ testApp.launchViaIntent(wmHelper)
+ }
+ }
+ transitions {
+ device.pressBack()
+ wmHelper.waitForHomeActivityVisible()
+ }
+ teardown {
+ eachRun {
+ this.setRotation(Surface.ROTATION_0)
+ }
+ test {
+ testApp.exit()
+ }
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun launcherReplacesAppWindowAsTopWindow() =
+ testSpec.launcherReplacesAppWindowAsTopWindow(testApp)
+
+ @Presubmit
+ @Test
+ fun wallpaperWindowBecomesVisible() = testSpec.wallpaperWindowBecomesVisible()
+
+ @Presubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ Surface.ROTATION_0)
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun wallpaperLayerReplacesAppLayer() = testSpec.wallpaperLayerReplacesAppLayer(testApp)
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerRotatesScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest(bugId = 173684672)
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ @FlakyTest(bugId = 173684672)
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<Array<Any>> {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val testApp = SimpleAppHelper(instrumentation)
- return FlickerTestRunnerFactory.getInstance()
- .buildTest(instrumentation, repetitions = 5) { configuration ->
- withTestName { buildTestTag(configuration) }
- repeat { configuration.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
- eachRun {
- this.setRotation(configuration.startRotation)
- testApp.launchViaIntent(wmHelper)
- }
- }
- transitions {
- device.pressBack()
- wmHelper.waitForHomeActivityVisible()
- }
- teardown {
- eachRun {
- this.setRotation(Surface.ROTATION_0)
- }
- test {
- testApp.exit()
- }
- }
- assertions {
- val isRotated = configuration.startRotation.isRotated()
-
- presubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- launcherReplacesAppWindowAsTopWindow(testApp)
- wallpaperWindowBecomesVisible()
- }
-
- layersTrace {
- noUncoveredRegions(configuration.startRotation,
- Surface.ROTATION_0)
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- wallpaperLayerReplacesAppLayer(testApp)
-
- if (!isRotated) {
- navBarLayerRotatesAndScales(configuration.startRotation,
- Surface.ROTATION_0)
- statusBarLayerRotatesScales(configuration.startRotation,
- Surface.ROTATION_0)
- }
- }
- }
-
- flaky {
- windowManagerTrace {
- visibleWindowsShownMoreThanOneConsecutiveEntry(bugId = 173684672)
- }
-
- layersTrace {
- visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 173684672)
-
- if (isRotated) {
- navBarLayerRotatesAndScales(configuration.startRotation,
- Surface.ROTATION_0)
- statusBarLayerRotatesScales(configuration.startRotation,
- Surface.ROTATION_0)
- }
- }
- }
- }
- }
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
}
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index d1c3efe35c54..08d2b7c206bf 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -16,12 +16,17 @@
package com.android.server.wm.flicker.close
+import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
-import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
@@ -36,12 +41,12 @@ import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.helpers.buildTestTag
-import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
+import org.junit.Assume
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -50,88 +55,121 @@ import org.junit.runners.Parameterized
* Test app closes by pressing home button.
* To run this test: `atest FlickerTests:CloseAppHomeButtonTest`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseAppHomeButtonTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
+class CloseAppHomeButtonTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = SimpleAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ transitions {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ }
+ teardown {
+ eachRun {
+ this.setRotation(Surface.ROTATION_0)
+ }
+ test {
+ testApp.exit()
+ }
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun launcherReplacesAppWindowAsTopWindow() =
+ testSpec.launcherReplacesAppWindowAsTopWindow(testApp)
+
+ @Presubmit
+ @Test
+ fun wallpaperWindowBecomesVisible() = testSpec.wallpaperWindowBecomesVisible()
+
+ @Presubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(
+ testSpec.config.startRotation, Surface.ROTATION_0)
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun wallpaperLayerReplacesAppLayer() = testSpec.wallpaperLayerReplacesAppLayer(testApp)
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerRotatesScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest(bugId = 173689015)
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ @FlakyTest(bugId = 173689015)
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<Array<Any>> {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val testApp = SimpleAppHelper(instrumentation)
- return FlickerTestRunnerFactory.getInstance()
- .buildTest(instrumentation, repetitions = 5) { configuration ->
- withTestName { buildTestTag(configuration) }
- repeat { configuration.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
- eachRun {
- testApp.launchViaIntent(wmHelper)
- this.setRotation(configuration.startRotation)
- }
- }
- transitions {
- device.pressHome()
- wmHelper.waitForHomeActivityVisible()
- }
- teardown {
- eachRun {
- this.setRotation(Surface.ROTATION_0)
- }
- test {
- testApp.exit()
- }
- }
- assertions {
- val isRotated = configuration.startRotation.isRotated()
-
- presubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- launcherReplacesAppWindowAsTopWindow(testApp)
- wallpaperWindowBecomesVisible()
- }
-
- layersTrace {
- noUncoveredRegions(configuration.startRotation,
- Surface.ROTATION_0)
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- wallpaperLayerReplacesAppLayer(testApp)
-
- if (!isRotated) {
- navBarLayerRotatesAndScales(configuration.startRotation,
- Surface.ROTATION_0)
- statusBarLayerRotatesScales(configuration.startRotation,
- Surface.ROTATION_0)
- }
- }
- }
-
- flaky {
- windowManagerTrace {
- visibleWindowsShownMoreThanOneConsecutiveEntry(bugId = 173689015)
- }
- layersTrace {
- visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 173689015)
-
- if (isRotated) {
- navBarLayerRotatesAndScales(configuration.startRotation,
- Surface.ROTATION_0)
- statusBarLayerRotatesScales(configuration.startRotation,
- Surface.ROTATION_0)
- }
- }
- }
- }
- }
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
}
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
index 323236ed9962..f7e749311442 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
@@ -16,13 +16,9 @@
package com.android.server.wm.flicker.helpers
-import android.os.Bundle
import android.os.RemoteException
-import android.platform.helpers.IAppHelper
import android.view.Surface
import com.android.server.wm.flicker.Flicker
-import com.android.server.wm.flicker.endRotation
-import com.android.server.wm.flicker.startRotation
/**
* Changes the device [rotation] and wait for the rotation animation to complete
@@ -47,128 +43,4 @@ fun Flicker.setRotation(rotation: Int) {
} catch (e: RemoteException) {
throw RuntimeException(e)
}
-}
-
-/**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param app App being launcher
- * @param beginRotation Initial screen rotation
- * @param endRotation End screen rotation (if any, otherwise use same as initial)
- *
- * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
-</END_ROTATION></BEGIN_ROTATION></APP></NAME> */
-fun buildTestTag(
- testName: String,
- app: IAppHelper,
- beginRotation: Int,
- endRotation: Int
-): String {
- return buildTestTag(
- testName, app.launcherName, beginRotation, endRotation, app2 = null, extraInfo = "")
-}
-
-/**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param configuration Configuration for the test
- * @param extraInfo Additional information to append to the tag
- *
- * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
-</END_ROTATION></BEGIN_ROTATION></APP></NAME> */
-@JvmOverloads
-fun buildTestTag(
- testName: String,
- configuration: Bundle,
- extraInfo: String = ""
-): String {
- return buildTestTag(testName,
- app = null,
- beginRotation = configuration.startRotation,
- endRotation = configuration.endRotation,
- app2 = null,
- extraInfo = extraInfo)
-}
-
-/**
- * Build a test tag for the test
- * @param configuration Configuration for the test
- * @param extraInfo Additional information to append to the tag
- *
- * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
-</END_ROTATION></BEGIN_ROTATION></APP></NAME> */
-@JvmOverloads
-fun buildTestTag(
- configuration: Bundle,
- extraInfo: String = ""
-): String {
- return buildTestTag(testName = null,
- app = null,
- beginRotation = configuration.startRotation,
- endRotation = configuration.endRotation,
- app2 = null,
- extraInfo = extraInfo)
-}
-
-/**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param app App being launcher
- * @param configuration Configuration for the test
- * @param extraInfo Additional information to append to the tag
- *
- * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
-</END_ROTATION></BEGIN_ROTATION></APP></NAME> */
-@JvmOverloads
-fun buildTestTag(
- testName: String,
- app: IAppHelper?,
- configuration: Bundle,
- extraInfo: String = ""
-): String {
- return buildTestTag(testName, app?.launcherName ?: "", configuration.startRotation,
- configuration.endRotation, app2 = null, extraInfo = extraInfo)
-}
-
-/**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param app App being launcher
- * @param app2 Second app being launched (if any)
- * @param beginRotation Initial screen rotation
- * @param endRotation End screen rotation (if any, otherwise use same as initial)
- * @param extraInfo Additional information to append to the tag
- *
- * @return test tag with pattern <NAME>__<APP></APP>(S)>__<ROTATION></ROTATION>(S)>[__<EXTRA>]
-</EXTRA></NAME> */
-fun buildTestTag(
- testName: String?,
- app: String?,
- beginRotation: Int,
- endRotation: Int,
- app2: String?,
- extraInfo: String
-): String {
- var testTag = ""
- if (testName != null) {
- testTag += testName
- }
- if (app != null) {
- testTag += "__$app"
- }
- if (app2 != null) {
- testTag += "-$app2"
- }
- testTag += "__${Surface.rotationToString(beginRotation)}"
- if (endRotation != beginRotation) {
- testTag += "-${Surface.rotationToString(endRotation)}"
- }
- if (extraInfo.isNotEmpty()) {
- testTag += "__$extraInfo"
- }
-
- if (testTag.startsWith("__")) {
- testTag = testTag.drop(2)
- }
- return testTag
-}
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index c7736f825e27..47eaddfa1f3a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -16,14 +16,19 @@
package com.android.server.wm.flicker.ime
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
-import com.android.server.wm.flicker.helpers.buildTestTag
-import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
@@ -37,7 +42,9 @@ import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import org.junit.Assume
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -48,79 +55,116 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeAutoOpenWindowToAppTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
+class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ testApp.openIME(device, wmHelper)
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ teardown {
+ test {
+ testApp.exit()
+ wmHelper.waitForAppTransitionIdle()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ transitions {
+ testApp.closeIME(device, wmHelper)
+ }
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
+
+ @Postsubmit
+ @Test
+ fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp)
+
+ @Postsubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
+
+ @Postsubmit
+ @Test
+ fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+
+ @Postsubmit
+ @Test
+ fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp)
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ }
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
+ }
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerRotatesScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
+ }
+
+ @FlakyTest
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<Array<Any>> {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- return FlickerTestRunnerFactory.getInstance()
- .buildTest(instrumentation, repetitions = 5) { configuration ->
- val testApp = ImeAppAutoFocusHelper(instrumentation,
- configuration.startRotation)
- withTestName { buildTestTag(configuration) }
- repeat { configuration.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
- eachRun {
- testApp.launchViaIntent(wmHelper)
- testApp.openIME(device, wmHelper)
- this.setRotation(configuration.startRotation)
- }
- }
- teardown {
- test {
- testApp.exit()
- wmHelper.waitForAppTransitionIdle()
- this.setRotation(Surface.ROTATION_0)
- }
- }
- transitions {
- testApp.closeIME(device, wmHelper)
- }
- assertions {
- val isRotated = configuration.startRotation.isRotated()
-
- postsubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry(
- listOf(IME_WINDOW_TITLE))
- imeAppWindowIsAlwaysVisible(testApp)
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(configuration.startRotation)
- imeLayerBecomesInvisible()
- imeAppLayerIsAlwaysVisible(testApp)
- if (!isRotated) {
- navBarLayerRotatesAndScales(configuration.startRotation)
- statusBarLayerRotatesScales(configuration.startRotation)
- }
- }
- }
-
- flaky {
- layersTrace {
- visibleLayersShownMoreThanOneConsecutiveEntry()
-
- if (isRotated) {
- navBarLayerRotatesAndScales(configuration.startRotation)
- statusBarLayerRotatesScales(configuration.startRotation)
- }
- }
- }
- }
- }
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
}
}
-} \ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index aa24456c652f..38a88d372da4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -16,14 +16,18 @@
package com.android.server.wm.flicker.ime
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
-import com.android.server.wm.flicker.helpers.buildTestTag
-import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
@@ -37,7 +41,9 @@ import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import org.junit.Assume
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -48,93 +54,151 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeAutoOpenWindowToHomeTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
+class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ testApp.openIME(device, wmHelper)
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ teardown {
+ test {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ transitions {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ wmHelper.waitImeWindowGone()
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
+
+ @Presubmit
+ @Test
+ fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
+
+ @Presubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ Surface.ROTATION_0)
+
+ @Presubmit
+ @Test
+ fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp)
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerRotatesScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.navBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ fun navBarLayerIsAlwaysVisible_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.navBarLayerIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.statusBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerIsAlwaysVisible_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.statusBarLayerIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
+ }
+
+ @FlakyTest
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
+ }
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<Array<Any>> {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- return FlickerTestRunnerFactory.getInstance()
- .buildTest(instrumentation, repetitions = 5) { configuration ->
- val testApp = ImeAppAutoFocusHelper(instrumentation,
- configuration.startRotation)
- withTestName {
- buildTestTag(configuration)
- }
- repeat { configuration.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
- eachRun {
- testApp.launchViaIntent(wmHelper)
- testApp.openIME(device, wmHelper)
- this.setRotation(configuration.startRotation)
- }
- }
- teardown {
- test {
- testApp.exit()
- this.setRotation(Surface.ROTATION_0)
- }
- }
- transitions {
- device.pressHome()
- wmHelper.waitForHomeActivityVisible()
- wmHelper.waitImeWindowGone()
- }
- assertions {
- val isRotated = configuration.startRotation.isRotated()
-
- presubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry(
- listOf(IME_WINDOW_TITLE))
-
- imeWindowBecomesInvisible()
- imeAppWindowBecomesInvisible(testApp)
- }
-
- layersTrace {
- noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0)
- imeLayerBecomesInvisible()
- imeAppLayerBecomesInvisible(testApp)
-
- if (!isRotated) {
- navBarLayerRotatesAndScales(configuration.startRotation,
- Surface.ROTATION_0)
- statusBarLayerRotatesScales(configuration.startRotation,
- Surface.ROTATION_0)
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(IME_WINDOW_TITLE))
- }
- }
- }
-
- flaky {
- layersTrace {
- if (isRotated) {
- navBarLayerRotatesAndScales(configuration.startRotation,
- Surface.ROTATION_0)
- statusBarLayerRotatesScales(configuration.startRotation,
- Surface.ROTATION_0)
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(IME_WINDOW_TITLE))
- }
- }
- }
- }
- }
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 2bd5abb640e5..476708c42c4c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -16,13 +16,18 @@
package com.android.server.wm.flicker.ime
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -33,10 +38,10 @@ import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEn
import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -47,63 +52,97 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeWindowToAppTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
+class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.launchViaIntent()
+ this.setRotation(testSpec.config.startRotation)
+ }
+ eachRun {
+ testApp.openIME(device, wmHelper)
+ }
+ }
+ teardown {
+ test {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ transitions {
+ testApp.closeIME(device, wmHelper)
+ }
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
+
+ @Postsubmit
+ @Test
+ fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp)
+
+ @Postsubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales() =
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerRotatesScales() =
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
+
+ @Postsubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @Postsubmit
+ @Test
+ fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+
+ @Postsubmit
+ @Test
+ fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp)
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<Array<Any>> {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val testApp = ImeAppHelper(instrumentation)
- return FlickerTestRunnerFactory.getInstance()
- .buildTest(instrumentation, repetitions = 5) { configuration ->
- withTestName { buildTestTag(configuration) }
- repeat { configuration.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- testApp.launchViaIntent()
- this.setRotation(configuration.startRotation)
- }
- eachRun {
- testApp.openIME(device, wmHelper)
- }
- }
- teardown {
- test {
- testApp.exit()
- this.setRotation(Surface.ROTATION_0)
- }
- }
- transitions {
- testApp.closeIME(device, wmHelper)
- }
- assertions {
- postsubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry(
- listOf(IME_WINDOW_TITLE))
- imeAppWindowIsAlwaysVisible(testApp)
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(configuration.startRotation)
- navBarLayerRotatesAndScales(configuration.startRotation)
- statusBarLayerRotatesScales(configuration.startRotation)
- visibleLayersShownMoreThanOneConsecutiveEntry()
- imeLayerBecomesInvisible()
- imeAppLayerIsAlwaysVisible(testApp)
- }
- }
- }
- }
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
}
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 7b61bb58446c..ac140f505076 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -16,28 +16,33 @@
package com.android.server.wm.flicker.ime
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.helpers.buildTestTag
-import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import org.junit.Assume
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -47,90 +52,126 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeWindowToHomeTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
+class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ this.setRotation(testSpec.config.startRotation)
+ testApp.openIME(device, wmHelper)
+ }
+ }
+ transitions {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ wmHelper.waitImeWindowGone()
+ }
+ teardown {
+ eachRun {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ }
+ test {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
+
+ @Postsubmit
+ @Test
+ fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
+
+ @Postsubmit
+ @Test
+ fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
+
+ @Postsubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ Surface.ROTATION_0)
+
+ @Postsubmit
+ @Test
+ fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+
+ @Postsubmit
+ @Test
+ fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp)
+
+ @Postsubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Postsubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerRotatesScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<Array<Any>> {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val testApp = ImeAppHelper(instrumentation)
- return FlickerTestRunnerFactory.getInstance()
- .buildTest(instrumentation, repetitions = 5) { configuration ->
- withTestName { buildTestTag(configuration) }
- repeat { configuration.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
- eachRun {
- testApp.launchViaIntent(wmHelper)
- this.setRotation(configuration.startRotation)
- testApp.openIME(device, wmHelper)
- }
- }
- transitions {
- device.pressHome()
- wmHelper.waitForHomeActivityVisible()
- wmHelper.waitImeWindowGone()
- }
- teardown {
- eachRun {
- device.pressHome()
- wmHelper.waitForHomeActivityVisible()
- }
- test {
- testApp.exit()
- this.setRotation(Surface.ROTATION_0)
- }
- }
- assertions {
- val isRotated = configuration.startRotation.isRotated()
-
- postsubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry(
- listOf(IME_WINDOW_TITLE))
- imeWindowBecomesInvisible()
- imeAppWindowBecomesInvisible(testApp)
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- imeLayerBecomesInvisible()
- imeAppLayerBecomesInvisible(testApp)
- noUncoveredRegions(configuration.startRotation,
- Surface.ROTATION_0)
-
- if (!isRotated) {
- navBarLayerRotatesAndScales(configuration.startRotation,
- Surface.ROTATION_0)
- statusBarLayerRotatesScales(configuration.startRotation,
- Surface.ROTATION_0)
- }
- }
- }
-
- flaky {
- layersTrace {
- visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(IME_WINDOW_TITLE))
-
- if (isRotated) {
- navBarLayerRotatesAndScales(configuration.startRotation,
- Surface.ROTATION_0)
- statusBarLayerRotatesScales(configuration.startRotation,
- Surface.ROTATION_0)
- }
- }
- }
- }
- }
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
}
}
-} \ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
index cfdd8564128f..212644c04505 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
@@ -17,85 +17,75 @@
package com.android.server.wm.flicker.ime
import android.platform.helpers.IAppHelper
-import com.android.server.wm.flicker.dsl.LayersAssertionBuilder
-import com.android.server.wm.flicker.dsl.WmAssertionBuilder
+import com.android.server.wm.flicker.FlickerTestParameter
const val IME_WINDOW_TITLE = "InputMethod"
-@JvmOverloads
-fun LayersAssertionBuilder.imeLayerBecomesVisible(bugId: Int = 0) {
- all("imeLayerBecomesVisible", bugId) {
+fun FlickerTestParameter.imeLayerBecomesVisible() {
+ assertLayers {
this.hidesLayer(IME_WINDOW_TITLE)
- .then()
- .showsLayer(IME_WINDOW_TITLE)
+ .then()
+ .showsLayer(IME_WINDOW_TITLE)
}
}
-@JvmOverloads
-fun LayersAssertionBuilder.imeLayerBecomesInvisible(bugId: Int = 0) {
- all("imeLayerBecomesInvisible", bugId) {
+fun FlickerTestParameter.imeLayerBecomesInvisible() {
+ assertLayers {
this.showsLayer(IME_WINDOW_TITLE)
- .then()
- .hidesLayer(IME_WINDOW_TITLE)
+ .then()
+ .hidesLayer(IME_WINDOW_TITLE)
}
}
-@JvmOverloads
-fun LayersAssertionBuilder.imeAppLayerIsAlwaysVisible(testApp: IAppHelper, bugId: Int = 0) {
- all("imeAppLayerIsAlwaysVisible", bugId) {
+fun FlickerTestParameter.imeAppLayerIsAlwaysVisible(testApp: IAppHelper) {
+ assertLayers {
this.showsLayer(testApp.getPackage())
}
}
-@JvmOverloads
-fun WmAssertionBuilder.imeAppWindowIsAlwaysVisible(testApp: IAppHelper, bugId: Int = 0) {
- all("imeAppWindowIsAlwaysVisible", bugId) {
+fun FlickerTestParameter.imeAppWindowIsAlwaysVisible(testApp: IAppHelper) {
+ assertWm {
this.showsAppWindowOnTop(testApp.getPackage())
}
}
-@JvmOverloads
-fun WmAssertionBuilder.imeWindowBecomesVisible(bugId: Int = 0) {
- all("imeWindowBecomesVisible", bugId) {
+fun FlickerTestParameter.imeWindowBecomesVisible() {
+ assertWm {
this.hidesNonAppWindow(IME_WINDOW_TITLE)
- .then()
- .showsNonAppWindow(IME_WINDOW_TITLE)
+ .then()
+ .showsNonAppWindow(IME_WINDOW_TITLE)
}
}
-@JvmOverloads
-fun WmAssertionBuilder.imeWindowBecomesInvisible(bugId: Int = 0) {
- all("imeWindowBecomesInvisible", bugId) {
+fun FlickerTestParameter.imeWindowBecomesInvisible() {
+ assertWm {
this.showsNonAppWindow(IME_WINDOW_TITLE)
- .then()
- .hidesNonAppWindow(IME_WINDOW_TITLE)
+ .then()
+ .hidesNonAppWindow(IME_WINDOW_TITLE)
}
}
-@JvmOverloads
-fun WmAssertionBuilder.imeAppWindowBecomesVisible(windowName: String, bugId: Int = 0) {
- all("imeAppWindowBecomesVisible", bugId) {
+fun FlickerTestParameter.imeAppWindowBecomesVisible(windowName: String) {
+ assertWm {
this.hidesAppWindow(windowName)
- .then()
- .showsAppWindow(windowName)
+ .then()
+ .showsAppWindow(windowName)
}
}
-@JvmOverloads
-fun WmAssertionBuilder.imeAppWindowBecomesInvisible(testApp: IAppHelper, bugId: Int = 0) {
- all("imeAppWindowBecomesInvisible", bugId) {
+fun FlickerTestParameter.imeAppWindowBecomesInvisible(testApp: IAppHelper) {
+ assertWm {
this.showsAppWindowOnTop(testApp.getPackage())
- .then()
- .appWindowNotOnTop(testApp.getPackage())
+ .then()
+ .appWindowNotOnTop(testApp.getPackage())
}
}
-@JvmOverloads
-fun LayersAssertionBuilder.imeAppLayerBecomesInvisible(testApp: IAppHelper, bugId: Int = 0) {
- all("imeAppLayerBecomesInvisible", bugId) {
+fun FlickerTestParameter.imeAppLayerBecomesInvisible(testApp: IAppHelper) {
+ assertLayers {
this.skipUntilFirstAssertion()
- .showsLayer(testApp.getPackage())
- .then()
- .hidesLayer(testApp.getPackage())
+ .showsLayer(testApp.getPackage())
+ .then()
+ .hidesLayer(testApp.getPackage())
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 9e94d6e49527..c7a5178a6693 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -16,13 +16,17 @@
package com.android.server.wm.flicker.ime
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -32,14 +36,16 @@ import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEn
import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop
-import com.android.server.wm.flicker.helpers.isRotated
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.layerAlwaysVisible
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import org.junit.Assume
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -50,80 +56,119 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenImeWindowTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
+class OpenImeWindowTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.launchViaIntent(wmHelper)
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ transitions {
+ testApp.openIME(device, wmHelper)
+ }
+ teardown {
+ eachRun {
+ testApp.closeIME(device, wmHelper)
+ }
+ test {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun imeWindowBecomesVisible() = testSpec.imeWindowBecomesVisible()
+
+ @Postsubmit
+ @Test
+ fun appWindowAlwaysVisibleOnTop() = testSpec.appWindowAlwaysVisibleOnTop(testApp.`package`)
+
+ @Postsubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
+
+ @Postsubmit
+ @Test
+ fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
+
+ @Postsubmit
+ @Test
+ fun layerAlwaysVisible() = testSpec.layerAlwaysVisible(testApp.`package`)
+
+ @Postsubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ }
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ }
+
+ @Postsubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
+ }
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerRotatesScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
+ }
+
+ @FlakyTest
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @FlakyTest
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<Array<Any>> {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val testApp = ImeAppHelper(instrumentation)
- return FlickerTestRunnerFactory.getInstance()
- .buildTest(instrumentation, repetitions = 5) { configuration ->
- withTestName { buildTestTag(configuration) }
- repeat { configuration.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- testApp.launchViaIntent(wmHelper)
- this.setRotation(configuration.startRotation)
- }
- }
- transitions {
- testApp.openIME(device, wmHelper)
- }
- teardown {
- eachRun {
- testApp.closeIME(device, wmHelper)
- }
- test {
- testApp.exit()
- this.setRotation(Surface.ROTATION_0)
- }
- }
- assertions {
- val isRotated = configuration.startRotation.isRotated()
-
- postsubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
-
- imeWindowBecomesVisible()
- appWindowAlwaysVisibleOnTop(testApp.`package`)
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(configuration.startRotation)
- imeLayerBecomesVisible()
- layerAlwaysVisible(testApp.`package`)
-
- if (!isRotated) {
- navBarLayerRotatesAndScales(configuration.startRotation)
- statusBarLayerRotatesScales(configuration.startRotation)
- }
- }
- }
-
- flaky {
- windowManagerTrace {
- visibleWindowsShownMoreThanOneConsecutiveEntry()
- }
- layersTrace {
- visibleLayersShownMoreThanOneConsecutiveEntry()
-
- if (isRotated) {
- navBarLayerRotatesAndScales(configuration.startRotation)
- statusBarLayerRotatesScales(configuration.startRotation)
- }
- }
- }
- }
- }
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 52549a23c9bb..0cd5d7999a58 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -16,14 +16,18 @@
package com.android.server.wm.flicker.ime
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -31,18 +35,20 @@ import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.endRotation
-import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.testapp.ActivityOptions
+import org.junit.Assume
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -53,89 +59,132 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ReOpenImeWindowTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
+class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
+ private val testAppComponentName = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.launchViaIntent(wmHelper)
+ testApp.openIME(device, wmHelper)
+ }
+ eachRun {
+ device.pressRecentApps()
+ wmHelper.waitImeWindowGone()
+ wmHelper.waitForAppTransitionIdle()
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ transitions {
+ device.reopenAppFromOverview(wmHelper)
+ wmHelper.waitImeWindowShown()
+ }
+ teardown {
+ test {
+ this.setRotation(Surface.ROTATION_0)
+ testApp.exit()
+ }
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ @Presubmit
+ @Test
+ fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun imeWindowBecomesVisible() = testSpec.imeWindowBecomesVisible()
+
+ @Presubmit
+ @Test
+ fun imeAppWindowBecomesVisible() =
+ testSpec.imeAppWindowBecomesVisible(testAppComponentName.className)
+
+ @Presubmit
+ @Test
+ // During testing the launcher is always in portrait mode
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ testSpec.config.endRotation)
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
+
+ @Presubmit
+ @Test
+ fun appLayerReplacesWallpaperLayer() =
+ testSpec.appLayerReplacesWallpaperLayer(testAppComponentName.className)
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerRotatesScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @FlakyTest
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<Array<Any>> {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val testAppComponentName = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME
- return FlickerTestRunnerFactory.getInstance()
- .buildTest(instrumentation, repetitions = 1) { configuration ->
- val testApp = ImeAppAutoFocusHelper(instrumentation,
- configuration.startRotation)
- withTestName { buildTestTag(configuration) }
- repeat { configuration.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- testApp.launchViaIntent(wmHelper)
- testApp.openIME(device, wmHelper)
- }
- eachRun {
- device.pressRecentApps()
- wmHelper.waitImeWindowGone()
- wmHelper.waitForAppTransitionIdle()
- this.setRotation(configuration.startRotation)
- }
- }
- transitions {
- device.reopenAppFromOverview(wmHelper)
- wmHelper.waitImeWindowShown()
- }
- teardown {
- test {
- this.setRotation(Surface.ROTATION_0)
- testApp.exit()
- }
- }
- assertions {
- val isRotated = configuration.startRotation.isRotated()
-
- presubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- imeWindowBecomesVisible()
- imeAppWindowBecomesVisible(testAppComponentName.className)
- wallpaperWindowBecomesInvisible()
- }
-
- layersTrace {
- noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation)
- statusBarLayerIsAlwaysVisible()
- navBarLayerIsAlwaysVisible()
- imeLayerBecomesVisible()
- appLayerReplacesWallpaperLayer(testAppComponentName.className)
-
- if (!isRotated) {
- navBarLayerRotatesAndScales(Surface.ROTATION_0,
- configuration.endRotation)
- statusBarLayerRotatesScales(Surface.ROTATION_0,
- configuration.endRotation)
- }
- }
- }
-
- flaky {
- layersTrace {
- visibleLayersShownMoreThanOneConsecutiveEntry()
-
- if (isRotated) {
- navBarLayerRotatesAndScales(Surface.ROTATION_0,
- configuration.endRotation)
- statusBarLayerRotatesScales(Surface.ROTATION_0,
- configuration.endRotation)
- }
- }
- }
- }
- }
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 1)
}
}
-} \ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
index be3fa5fa3cdf..130860d31ac1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
@@ -17,12 +17,12 @@
package com.android.server.wm.flicker.launch
import android.platform.helpers.IAppHelper
-import com.android.server.wm.flicker.dsl.WmAssertionBuilder
+import com.android.server.wm.flicker.FlickerTestParameter
-fun WmAssertionBuilder.appWindowReplacesLauncherAsTopWindow(testApp: IAppHelper, bugId: Int = 0) {
- all("appWindowReplacesLauncherAsTopWindow", bugId) {
+fun FlickerTestParameter.appWindowReplacesLauncherAsTopWindow(testApp: IAppHelper) {
+ assertWm {
this.showsAppWindowOnTop("Launcher")
- .then()
- .showsAppWindowOnTop("Snapshot", testApp.getPackage())
+ .then()
+ .showsAppWindowOnTop("Snapshot", testApp.getPackage())
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 0ec0b04339cd..74f002d67229 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -16,14 +16,17 @@
package com.android.server.wm.flicker.launch
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.focusChanges
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -39,9 +42,11 @@ import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEn
import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SimpleAppHelper
-import com.android.server.wm.flicker.helpers.isRotated
+import org.junit.Assume
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -52,85 +57,122 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppColdTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
+class OpenAppColdTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = SimpleAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ transitions {
+ testApp.launchViaIntent(wmHelper)
+ // wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ wmHelper.waitForAppTransitionIdle()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ @Presubmit
+ @Test
+ fun appWindowReplacesLauncherAsTopWindow() =
+ testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
+
+ @Presubmit
+ @Test
+ fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible()
+
+ @Presubmit
+ @Test
+ // During testing the launcher is always in portrait mode
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ Surface.ROTATION_0)
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun appLayerReplacesWallpaperLayer() =
+ testSpec.appLayerReplacesWallpaperLayer(testApp.`package`)
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerRotatesScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
+
+ @FlakyTest
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<Array<Any>> {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val testApp = SimpleAppHelper(instrumentation)
- return FlickerTestRunnerFactory.getInstance()
- .buildTest(instrumentation) { configuration ->
- withTestName { buildTestTag(configuration) }
- repeat { configuration.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
- eachRun {
- this.setRotation(configuration.startRotation)
- }
- }
- transitions {
- testApp.open()
- wmHelper.waitForFullScreenApp(testApp.component)
- }
- teardown {
- eachRun {
- testApp.exit()
- wmHelper.waitForAppTransitionIdle()
- this.setRotation(Surface.ROTATION_0)
- }
- }
- assertions {
- val isRotated = configuration.startRotation.isRotated()
-
- presubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry()
- appWindowReplacesLauncherAsTopWindow(testApp)
- wallpaperWindowBecomesInvisible()
- }
-
- layersTrace {
- // During testing the launcher is always in portrait mode
- noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation)
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- appLayerReplacesWallpaperLayer(testApp.`package`)
-
- if (!isRotated) {
- navBarLayerRotatesAndScales(Surface.ROTATION_0,
- configuration.endRotation)
- statusBarLayerRotatesScales(Surface.ROTATION_0,
- configuration.endRotation)
- }
- }
-
- eventLog {
- focusChanges("NexusLauncherActivity", testApp.`package`)
- }
- }
-
- flaky {
- layersTrace {
- visibleLayersShownMoreThanOneConsecutiveEntry()
-
- if (isRotated) {
- navBarLayerRotatesAndScales(Surface.ROTATION_0,
- configuration.endRotation)
- statusBarLayerRotatesScales(Surface.ROTATION_0,
- configuration.endRotation)
- }
- }
- }
- }
- }
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 5fb050927dad..e2a258aea239 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -16,17 +16,22 @@
package com.android.server.wm.flicker.launch
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
-import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -40,9 +45,11 @@ import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SimpleAppHelper
-import com.android.server.wm.flicker.helpers.isRotated
+import org.junit.Assume
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -53,97 +60,115 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromOverviewTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
+class OpenAppFromOverviewTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = SimpleAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.launchViaIntent(wmHelper)
+ }
+ eachRun {
+ device.pressHome()
+ wmHelper.waitForAppTransitionIdle()
+ device.pressRecentApps()
+ wmHelper.waitForAppTransitionIdle()
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ transitions {
+ device.reopenAppFromOverview(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ teardown {
+ test {
+ testApp.exit()
+ }
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Test
+ fun appWindowReplacesLauncherAsTopWindow() =
+ testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
+
+ @Test
+ fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun appLayerReplacesWallpaperLayer() =
+ testSpec.appLayerReplacesWallpaperLayer(testApp.`package`)
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.statusBarLayerIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.navBarLayerIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
+
+ @Postsubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ @FlakyTest
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @FlakyTest(bugId = 141361128)
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(Surface.ROTATION_0,
+ testSpec.config.endRotation)
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<Array<Any>> {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val testApp = SimpleAppHelper(instrumentation)
- return FlickerTestRunnerFactory.getInstance()
- .buildTest(instrumentation, repetitions = 5) { configuration ->
- withTestName { buildTestTag(configuration) }
- repeat { configuration.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- testApp.launchViaIntent(wmHelper)
- }
- eachRun {
- device.pressHome()
- wmHelper.waitForAppTransitionIdle()
- device.pressRecentApps()
- wmHelper.waitForAppTransitionIdle()
- this.setRotation(configuration.startRotation)
- }
- }
- transitions {
- device.reopenAppFromOverview(wmHelper)
- wmHelper.waitForFullScreenApp(testApp.component)
- }
- teardown {
- test {
- testApp.exit()
- }
- }
- assertions {
- val isRotated = configuration.startRotation.isRotated()
-
- presubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- appWindowReplacesLauncherAsTopWindow(testApp)
- wallpaperWindowBecomesInvisible()
- }
-
- layersTrace {
- appLayerReplacesWallpaperLayer(testApp.`package`)
-
- if (!isRotated) {
- navBarLayerRotatesAndScales(Surface.ROTATION_0,
- configuration.endRotation)
- statusBarLayerRotatesScales(Surface.ROTATION_0,
- configuration.endRotation)
- } else {
- statusBarLayerIsAlwaysVisible()
- navBarLayerIsAlwaysVisible()
- }
- }
-
- eventLog {
- focusChanges("NexusLauncherActivity", testApp.`package`)
- }
- }
-
- postsubmit {
- windowManagerTrace {
- visibleWindowsShownMoreThanOneConsecutiveEntry()
- }
- }
-
- flaky {
- layersTrace {
- visibleLayersShownMoreThanOneConsecutiveEntry()
- noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation,
- bugId = 141361128)
-
- if (isRotated) {
- navBarLayerRotatesAndScales(Surface.ROTATION_0,
- configuration.endRotation)
- statusBarLayerRotatesScales(Surface.ROTATION_0,
- configuration.endRotation)
- } else {
- statusBarLayerIsAlwaysVisible()
- navBarLayerIsAlwaysVisible()
- }
- }
- }
- }
- }
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
}
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 1f375a5cdea8..386dafc590af 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -16,14 +16,17 @@
package com.android.server.wm.flicker.launch
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.focusChanges
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -36,12 +39,13 @@ import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
+import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SimpleAppHelper
-import com.android.server.wm.flicker.helpers.isRotated
+import org.junit.Assume
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -52,89 +56,122 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppWarmTest(testSpec: FlickerTestRunnerFactory.TestSpec) : FlickerTestRunner(testSpec) {
+class OpenAppWarmTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = SimpleAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.launchViaIntent(wmHelper)
+ // wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ eachRun {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ transitions {
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ teardown {
+ eachRun {
+ this.setRotation(Surface.ROTATION_0)
+ }
+ test {
+ testApp.exit()
+ }
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ @Presubmit
+ @Test
+ fun appWindowReplacesLauncherAsTopWindow() =
+ testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
+
+ @Presubmit
+ @Test
+ fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible()
+
+ @Presubmit
+ @Test
+ // During testing the launcher is always in portrait mode
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ Surface.ROTATION_0)
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun appLayerReplacesWallpaperLayer() =
+ testSpec.appLayerReplacesWallpaperLayer(testApp.`package`)
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerRotatesScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<Array<Any>> {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val testApp = SimpleAppHelper(instrumentation)
- return FlickerTestRunnerFactory.getInstance()
- .buildTest(instrumentation) { configuration ->
- withTestName { buildTestTag(configuration) }
- repeat { configuration.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- testApp.open()
- wmHelper.waitForFullScreenApp(testApp.component)
- }
- eachRun {
- device.pressHome()
- wmHelper.waitForHomeActivityVisible()
- this.setRotation(configuration.startRotation)
- }
- }
- transitions {
- testApp.open()
- wmHelper.waitForFullScreenApp(testApp.component)
- }
- teardown {
- eachRun {
- this.setRotation(Surface.ROTATION_0)
- }
- test {
- testApp.exit()
- }
- }
- assertions {
- val isRotated = configuration.startRotation.isRotated()
-
- presubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- appWindowReplacesLauncherAsTopWindow(testApp)
- wallpaperWindowBecomesInvisible()
- }
-
- layersTrace {
- // During testing the launcher is always in portrait mode
- noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation)
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- appLayerReplacesWallpaperLayer(testApp.`package`)
-
- if (!isRotated) {
- navBarLayerRotatesAndScales(Surface.ROTATION_0,
- configuration.endRotation)
- statusBarLayerRotatesScales(Surface.ROTATION_0,
- configuration.endRotation)
- }
- }
-
- eventLog {
- focusChanges("NexusLauncherActivity", testApp.`package`)
- }
- }
-
- flaky {
- layersTrace {
- visibleLayersShownMoreThanOneConsecutiveEntry()
-
- if (isRotated) {
- navBarLayerRotatesAndScales(Surface.ROTATION_0,
- configuration.endRotation)
- statusBarLayerRotatesScales(Surface.ROTATION_0,
- configuration.endRotation)
- }
- }
- }
- }
- }
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 7bfdd96b9af8..3cc509fe2b8e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -17,28 +17,27 @@
package com.android.server.wm.flicker.rotation
import android.os.Bundle
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusDoesNotChange
import com.android.server.wm.flicker.helpers.SimpleAppHelper
-import com.android.server.wm.flicker.helpers.StandardAppHelper
-import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -49,78 +48,95 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class ChangeAppRotationTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : RotationTransition(InstrumentationRegistry.getInstrumentation()) {
- override val testApp: StandardAppHelper
- get() = SimpleAppHelper(instrumentation)
+ testSpec: FlickerTestParameter
+) : RotationTransition(testSpec) {
+ override val testApp = SimpleAppHelper(instrumentation)
+ override fun getAppLaunchParams(configuration: Bundle): Map<String, String> = emptyMap()
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ @Presubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ testSpec.config.endRotation, allStates = false)
+
+ @Presubmit
+ @Test
+ fun screenshotLayerBecomesInvisible() {
+ testSpec.assertLayers {
+ this.showsLayer(testApp.getPackage())
+ .then()
+ .showsLayer(SCREENSHOT_LAYER)
+ .then()
+ .showsLayer(testApp.getPackage())
+ }
+ }
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales(
+ testSpec.config.startRotation, testSpec.config.endRotation)
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(
+ testSpec.config.startRotation, testSpec.config.endRotation)
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun appLayerRotates_StartingPos() {
+ testSpec.assertLayersStart {
+ this.hasVisibleRegion(testApp.getPackage(), startingPos)
+ }
+ }
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun appLayerRotates_EndingPos() {
+ testSpec.assertLayersEnd {
+ this.hasVisibleRegion(testApp.getPackage(), endingPos)
+ }
+ }
- override fun getAppLaunchParams(configuration: Bundle): Map<String, String> = emptyMap()
+ @FlakyTest(bugId = 151179149)
+ @Test
+ fun focusDoesNotChange() = testSpec.focusDoesNotChange()
+ companion object {
private const val SCREENSHOT_LAYER = "RotationLayer"
- @Parameterized.Parameters(name = "{0}1}")
+ @Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName { buildTestTag(configuration) }
- assertions {
- presubmit {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry()
- }
-
- layersTrace {
- noUncoveredRegions(configuration.startRotation,
- configuration.endRotation, allStates = false)
-
- all("screenshotLayerBecomesInvisible") {
- this.showsLayer(testApp.getPackage())
- .then()
- .showsLayer(SCREENSHOT_LAYER)
- .then()
- .showsLayer(testApp.getPackage())
- }
- }
- }
-
- flaky {
- layersTrace {
- navBarLayerIsAlwaysVisible(bugId = 140855415)
- statusBarLayerIsAlwaysVisible(bugId = 140855415)
- navBarLayerRotatesAndScales(configuration.startRotation,
- configuration.endRotation, bugId = 140855415)
- statusBarLayerRotatesScales(configuration.startRotation,
- configuration.endRotation, bugId = 140855415)
- visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 140855415)
-
- val startingPos = WindowUtils.getDisplayBounds(
- configuration.startRotation)
- val endingPos = WindowUtils.getDisplayBounds(
- configuration.endRotation)
-
- start("appLayerRotates_StartingPos", bugId = 140855415) {
- this.hasVisibleRegion(testApp.getPackage(), startingPos)
- }
-
- end("appLayerRotates_EndingPos", bugId = 140855415) {
- this.hasVisibleRegion(testApp.getPackage(), endingPos)
- }
- }
-
- eventLog {
- focusDoesNotChange(bugId = 151179149)
- }
- }
- }
- }
-
- return FlickerTestRunnerFactory.getInstance()
- .buildRotationTest(instrumentation, transition, testSpec, repetitions = 5)
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigRotationTests(repetitions = 5)
}
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index b871e949cb19..04ab84dfcd8e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -18,29 +18,39 @@ package com.android.server.wm.flicker.rotation
import android.app.Instrumentation
import android.os.Bundle
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
-abstract class RotationTransition(protected val instrumentation: Instrumentation) {
- abstract val testApp: StandardAppHelper
- abstract fun getAppLaunchParams(configuration: Bundle): Map<String, String>
+abstract class RotationTransition(protected val testSpec: FlickerTestParameter) {
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ protected val startingPos get() = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ protected val endingPos get() = WindowUtils.getDisplayBounds(testSpec.config.endRotation)
- protected open val transition: FlickerBuilder.(Bundle) -> Unit
- get() = { configuration ->
- repeat { configuration.repetitions }
+ protected abstract val testApp: StandardAppHelper
+ protected abstract fun getAppLaunchParams(configuration: Bundle): Map<String, String>
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
setup {
test {
device.wakeUpAndGoToHomeScreen()
- val extras = getAppLaunchParams(configuration)
+ val extras = getAppLaunchParams(testSpec.config)
testApp.launchViaIntent(wmHelper, stringExtras = extras)
}
eachRun {
- this.setRotation(configuration.startRotation)
+ this.setRotation(testSpec.config.startRotation)
}
}
teardown {
@@ -49,7 +59,8 @@ abstract class RotationTransition(protected val instrumentation: Instrumentation
}
}
transitions {
- this.setRotation(configuration.endRotation)
+ this.setRotation(testSpec.config.endRotation)
}
}
+ }
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 78614640a372..ef1aeadb31bc 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -17,31 +17,30 @@
package com.android.server.wm.flicker.rotation
import android.os.Bundle
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusDoesNotChange
-import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop
-import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
-import com.android.server.wm.flicker.helpers.StandardAppHelper
import com.android.server.wm.flicker.layerAlwaysVisible
-import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -52,116 +51,108 @@ import org.junit.runners.Parameterized
*/
@RequiresDevice
@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class SeamlessAppRotationTest(
- testSpec: FlickerTestRunnerFactory.TestSpec
-) : FlickerTestRunner(testSpec) {
- companion object : RotationTransition(InstrumentationRegistry.getInstrumentation()) {
- override val testApp: StandardAppHelper
- get() = SeamlessRotationAppHelper(instrumentation)
+ testSpec: FlickerTestParameter
+) : RotationTransition(testSpec) {
+ override val testApp = SeamlessRotationAppHelper(instrumentation)
+
+ override fun getAppLaunchParams(configuration: Bundle): Map<String, String> = mapOf(
+ ActivityOptions.EXTRA_STARVE_UI_THREAD to configuration.starveUiThread.toString()
+ )
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ @Presubmit
+ @Test
+ fun appWindowAlwaysVisibleOnTop() = testSpec.appWindowAlwaysVisibleOnTop(testApp.`package`)
+
+ @Presubmit
+ @Test
+ fun layerAlwaysVisible() = testSpec.layerAlwaysVisible(testApp.`package`)
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @FlakyTest(bugId = 147659548)
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ testSpec.config.endRotation, allStates = false)
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales(
+ testSpec.config.startRotation, testSpec.config.endRotation)
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(
+ testSpec.config.startRotation, testSpec.config.endRotation)
+
+ @FlakyTest
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @FlakyTest(bugId = 147659548)
+ @Test
+ fun appLayerRotates() {
+ testSpec.assertLayers {
+ this.hasVisibleRegion(testApp.`package`, startingPos)
+ }
+ }
- override fun getAppLaunchParams(configuration: Bundle): Map<String, String> = mapOf(
- ActivityOptions.EXTRA_STARVE_UI_THREAD to configuration.starveUiThread.toString()
- )
+ @FlakyTest(bugId = 151179149)
+ @Test
+ fun focusDoesNotChange() = testSpec.focusDoesNotChange()
- private val testFactory = FlickerTestRunnerFactory.getInstance()
+ companion object {
+ private val testFactory = FlickerTestParameterFactory.getInstance()
private val Bundle.starveUiThread
get() = this.getBoolean(ActivityOptions.EXTRA_STARVE_UI_THREAD, false)
- private fun Bundle.createConfig(starveUiThread: Boolean): Bundle {
- val config = this.deepCopy()
+ private fun FlickerTestParameter.createConfig(starveUiThread: Boolean): Bundle {
+ val config = this.config.deepCopy()
config.putBoolean(ActivityOptions.EXTRA_STARVE_UI_THREAD, starveUiThread)
return config
}
@JvmStatic
- private fun getConfigurations(): List<Bundle> {
- return testFactory.getConfigRotationTests().flatMap {
+ private fun getConfigurations(): List<FlickerTestParameter> {
+ return testFactory.getConfigRotationTests(repetitions = 2).flatMap {
val defaultRun = it.createConfig(starveUiThread = false)
val busyUiRun = it.createConfig(starveUiThread = true)
- listOf(defaultRun, busyUiRun)
+ listOf(
+ FlickerTestParameter(defaultRun),
+ FlickerTestParameter(busyUiRun,
+ name = "${FlickerTestParameter.defaultName(busyUiRun)}_BUSY_UI_THREAD"
+ )
+ )
}
}
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<Array<Any>> {
- val configurations = getConfigurations()
- val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName {
- val extra = if (configuration.starveUiThread) {
- "BUSY_UI_THREAD"
- } else {
- ""
- }
- buildTestTag(configuration, extraInfo = extra)
- }
- assertions {
- val startingBounds = WindowUtils.getDisplayBounds(configuration.startRotation)
- val endingBounds = WindowUtils.getDisplayBounds(configuration.endRotation)
-
- presubmit {
- windowManagerTrace {
- visibleWindowsShownMoreThanOneConsecutiveEntry()
- appWindowAlwaysVisibleOnTop(testApp.`package`)
- }
-
- layersTrace {
- layerAlwaysVisible(testApp.`package`)
- }
- }
-
- flaky {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible(bugId = 140855415)
- statusBarWindowIsAlwaysVisible(bugId = 140855415)
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible(bugId = 140855415)
- statusBarLayerIsAlwaysVisible(bugId = 140855415)
- noUncoveredRegions(configuration.startRotation,
- configuration.endRotation, allStates = false, bugId = 147659548)
- navBarLayerRotatesAndScales(configuration.startRotation,
- configuration.endRotation)
- statusBarLayerRotatesScales(configuration.startRotation,
- configuration.endRotation)
- visibleLayersShownMoreThanOneConsecutiveEntry()
-
- all("appLayerRotates", bugId = 147659548) {
- if (startingBounds == endingBounds) {
- this.hasVisibleRegion(
- testApp.`package`, startingBounds)
- } else {
- this.hasVisibleRegion(testApp.`package`,
- startingBounds)
- .then()
- .hasVisibleRegion(testApp.`package`,
- endingBounds)
- }
- }
-
- all("noUncoveredRegions", bugId = 147659548) {
- if (startingBounds == endingBounds) {
- this.coversAtLeastRegion(startingBounds)
- } else {
- this.coversAtLeastRegion(startingBounds)
- .then()
- .coversAtLeastRegion(endingBounds)
- }
- }
- }
-
- eventLog {
- focusDoesNotChange(bugId = 151179149)
- }
- }
- }
- }
-
- return testFactory.buildRotationTest(instrumentation, transition, testSpec,
- deviceConfigurations = configurations, repetitions = 2)
+ fun getParams(): Collection<FlickerTestParameter> {
+ return getConfigurations()
}
}
-} \ No newline at end of file
+}
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index a72b07c45dd8..335c8d0127eb 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test {
name: "InputTests",
srcs: ["src/**/*.kt"],
diff --git a/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
index f919a3eaf271..c19e5cc34611 100644
--- a/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
+++ b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
@@ -62,15 +62,12 @@ class ViewFrameInfoTest {
fun testUpdateFrameInfoFromViewFrameInfo() {
val frameInfo = FrameInfo()
// By default, all values should be zero
- assertThat(frameInfo.frameInfo[FrameInfo.OLDEST_INPUT_EVENT]).isEqualTo(0)
- assertThat(frameInfo.frameInfo[FrameInfo.NEWEST_INPUT_EVENT]).isEqualTo(0)
+ // TODO(b/169866723): Use InputEventAssigner and assert INPUT_EVENT_ID
assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo(0)
assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isEqualTo(0)
// The values inside FrameInfo should match those from ViewFrameInfo after we update them
mViewFrameInfo.populateFrameInfo(frameInfo)
- assertThat(frameInfo.frameInfo[FrameInfo.OLDEST_INPUT_EVENT]).isEqualTo(10)
- assertThat(frameInfo.frameInfo[FrameInfo.NEWEST_INPUT_EVENT]).isEqualTo(20)
assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo(
FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED)
assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isGreaterThan(mTimeStarted)
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index 95044dc5e7bb..6e1cef496f40 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -105,6 +105,7 @@ apex {
key: "com.android.apex.apkrollback.test.key",
apps: ["TestAppAv1"],
installable: false,
+ updatable: false,
}
apex {
@@ -115,6 +116,7 @@ apex {
key: "com.android.apex.apkrollback.test.key",
apps: ["TestAppAv2"],
installable: false,
+ updatable: false,
}
apex {
@@ -125,4 +127,5 @@ apex {
key: "com.android.apex.apkrollback.test.key",
apps: ["TestAppACrashingV2"],
installable: false,
+ updatable: false,
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 0508125edfc8..0bb0337b3b09 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -35,7 +35,6 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.cts.install.lib.Install;
import com.android.cts.install.lib.InstallUtils;
import com.android.cts.install.lib.TestApp;
-import com.android.cts.install.lib.Uninstall;
import com.android.cts.rollback.lib.Rollback;
import com.android.cts.rollback.lib.RollbackUtils;
import com.android.internal.R;
@@ -89,7 +88,6 @@ public class StagedRollbackTest {
*/
@Test
public void testBadApkOnly_Phase1_Install() throws Exception {
- Uninstall.packages(TestApp.A);
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
Install.single(TestApp.A1).commit();
@@ -149,7 +147,6 @@ public class StagedRollbackTest {
*/
@Test
public void testNativeWatchdogTriggersRollback_Phase1_Install() throws Exception {
- Uninstall.packages(TestApp.A);
Install.single(TestApp.A1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
@@ -183,7 +180,6 @@ public class StagedRollbackTest {
*/
@Test
public void testNativeWatchdogTriggersRollbackForAll_Phase1_InstallA() throws Exception {
- Uninstall.packages(TestApp.A);
Install.single(TestApp.A1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
@@ -201,7 +197,6 @@ public class StagedRollbackTest {
TestApp.A)).isNotNull();
// Install another package with rollback
- Uninstall.packages(TestApp.B);
Install.single(TestApp.B1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
@@ -238,7 +233,6 @@ public class StagedRollbackTest {
@Test
public void testPreviouslyAbandonedRollbacks_Phase1_InstallAndAbandon() throws Exception {
- Uninstall.packages(TestApp.A);
Install.single(TestApp.A1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
@@ -265,7 +259,6 @@ public class StagedRollbackTest {
public void testPreviouslyAbandonedRollbacks_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
InstallUtils.processUserData(TestApp.A);
- Uninstall.packages(TestApp.A);
}
private static String getModuleMetadataPackageName() {
@@ -301,7 +294,6 @@ public class StagedRollbackTest {
@Test
public void testRollbackDataPolicy_Phase1_Install() throws Exception {
- Uninstall.packages(TestApp.A, TestApp.B, TestApp.C);
Install.multi(TestApp.A1, TestApp.B1, TestApp.C1).commit();
// Write user data version = 1
InstallUtils.processUserData(TestApp.A);
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 65fb7b6c8cc6..304567a34ed3 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -99,10 +99,16 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
"/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex");
runPhase("expireRollbacks");
mLogger.start(getDevice());
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A");
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.B");
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.C");
}
@After
public void tearDown() throws Exception {
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A");
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.B");
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.C");
mLogger.stop();
runPhase("expireRollbacks");
deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
@@ -283,7 +289,6 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
*/
@Test
public void testRollbackApexWithApk() throws Exception {
- getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A");
pushTestApex();
runPhase("testRollbackApexWithApk_Phase1_Install");
getDevice().reboot();
@@ -297,7 +302,6 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
*/
@Test
public void testRollbackApexWithApkCrashing() throws Exception {
- getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A");
pushTestApex();
// Install an apex with apk that crashes
diff --git a/tests/SilkFX/Android.bp b/tests/SilkFX/Android.bp
index 92e3efa7fd55..088d9a2d7f41 100644
--- a/tests/SilkFX/Android.bp
+++ b/tests/SilkFX/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test {
name: "SilkFX",
srcs: ["**/*.java", "**/*.kt"],
diff --git a/tests/SurfaceViewBufferTests/Android.bp b/tests/SurfaceViewBufferTests/Android.bp
index 48031de15f54..dc75f00e7cdc 100644
--- a/tests/SurfaceViewBufferTests/Android.bp
+++ b/tests/SurfaceViewBufferTests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test {
name: "SurfaceViewBufferTests",
srcs: ["**/*.java","**/*.kt"],
diff --git a/tests/UpdatableSystemFontTest/Android.bp b/tests/UpdatableSystemFontTest/Android.bp
index 43a5078c3c24..ee24d48f0ed5 100644
--- a/tests/UpdatableSystemFontTest/Android.bp
+++ b/tests/UpdatableSystemFontTest/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
java_test_host {
name: "UpdatableSystemFontTest",
srcs: ["src/**/*.java"],
diff --git a/tests/UpdatableSystemFontTest/testdata/Android.bp b/tests/UpdatableSystemFontTest/testdata/Android.bp
index 1296699e3c9f..f744d5dd2b51 100644
--- a/tests/UpdatableSystemFontTest/testdata/Android.bp
+++ b/tests/UpdatableSystemFontTest/testdata/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
filegroup {
name: "UpdatableSystemFontTestKeyPem",
srcs: ["UpdatableSystemFontTestKey.pem"],
diff --git a/tests/benchmarks/internal/Android.bp b/tests/benchmarks/internal/Android.bp
index 9c34eaf2af01..74ed7a34f626 100644
--- a/tests/benchmarks/internal/Android.bp
+++ b/tests/benchmarks/internal/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_test {
name: "InternalBenchTests",
srcs: ["src/**/*.java"],
@@ -23,4 +32,3 @@ android_test {
platform_apis: true,
certificate: "platform"
}
-
diff --git a/tests/net/common/java/android/net/NetworkStackTest.java b/tests/net/common/java/android/net/NetworkStackTest.java
index a99aa0106655..f8f9c72374ad 100644
--- a/tests/net/common/java/android/net/NetworkStackTest.java
+++ b/tests/net/common/java/android/net/NetworkStackTest.java
@@ -15,20 +15,8 @@
*/
package android.net;
-import static android.Manifest.permission.NETWORK_STACK;
-import static android.content.pm.PackageManager.PERMISSION_DENIED;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
-import static android.net.NetworkStack.checkNetworkStackPermission;
-import static android.net.NetworkStack.checkNetworkStackPermissionOr;
-
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.when;
-import android.content.Context;
import android.os.Build;
import android.os.IBinder;
@@ -46,44 +34,15 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class NetworkStackTest {
- private static final String [] OTHER_PERMISSION = {"otherpermission1", "otherpermission2"};
-
@Rule
public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
- @Mock Context mCtx;
@Mock private IBinder mConnectorBinder;
@Before public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
- @Test
- public void testCheckNetworkStackPermission() throws Exception {
- when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_GRANTED);
- when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK)))
- .thenReturn(PERMISSION_DENIED);
- checkNetworkStackPermission(mCtx);
- checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
-
- when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_DENIED);
- when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK)))
- .thenReturn(PERMISSION_GRANTED);
- checkNetworkStackPermission(mCtx);
- checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
-
- when(mCtx.checkCallingOrSelfPermission(any())).thenReturn(PERMISSION_DENIED);
-
- try {
- checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
- } catch (SecurityException e) {
- // Expect to get a SecurityException
- return;
- }
-
- fail("Expect fail but permission granted.");
- }
-
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testGetService() {
NetworkStack.setServiceForTest(mConnectorBinder);
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index 083c8c8741da..9ed55f098a16 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -38,6 +38,7 @@ import android.net.metrics.IpConnectivityLog
import android.os.ConditionVariable
import android.os.IBinder
import android.os.INetworkManagementService
+import android.os.SystemConfigManager
import android.os.UserHandle
import android.testing.TestableContext
import android.util.Log
@@ -57,6 +58,7 @@ import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.AdditionalAnswers
+import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.anyInt
@@ -94,6 +96,8 @@ class ConnectivityServiceIntegrationTest {
private lateinit var netd: INetd
@Mock
private lateinit var dnsResolver: IDnsResolver
+ @Mock
+ private lateinit var systemConfigManager: SystemConfigManager
@Spy
private var context = TestableContext(realContext)
@@ -151,6 +155,11 @@ class ConnectivityServiceIntegrationTest {
doReturn(UserHandle.ALL).`when`(asUserCtx).user
doReturn(asUserCtx).`when`(context).createContextAsUser(eq(UserHandle.ALL), anyInt())
doNothing().`when`(context).sendStickyBroadcast(any(), any())
+ doReturn(Context.SYSTEM_CONFIG_SERVICE).`when`(context)
+ .getSystemServiceName(SystemConfigManager::class.java)
+ doReturn(systemConfigManager).`when`(context)
+ .getSystemService(Context.SYSTEM_CONFIG_SERVICE)
+ doReturn(IntArray(0)).`when`(systemConfigManager).getSystemPermissionUids(anyString())
networkStackClient = TestNetworkStackClient(realContext)
networkStackClient.init()
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 24e559225027..6de1075d519b 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -53,6 +53,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
import static android.net.NetworkCapabilities.NET_CAPABILITY_IA;
@@ -238,6 +239,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.SystemClock;
+import android.os.SystemConfigManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -430,6 +432,7 @@ public class ConnectivityServiceTest {
@Mock EthernetManager mEthernetManager;
@Mock NetworkPolicyManager mNetworkPolicyManager;
@Mock KeyStore mKeyStore;
+ @Mock SystemConfigManager mSystemConfigManager;
private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -526,6 +529,7 @@ public class ConnectivityServiceTest {
if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
if (Context.ETHERNET_SERVICE.equals(name)) return mEthernetManager;
if (Context.NETWORK_POLICY_SERVICE.equals(name)) return mNetworkPolicyManager;
+ if (Context.SYSTEM_CONFIG_SERVICE.equals(name)) return mSystemConfigManager;
return super.getSystemService(name);
}
@@ -1432,6 +1436,7 @@ public class ConnectivityServiceTest {
applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
.thenReturn(applicationInfo);
+ when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
// InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
// http://b/25897652 .
@@ -2783,7 +2788,8 @@ public class ConnectivityServiceTest {
if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN ||
capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA ||
capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS ||
- capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP) {
+ capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP
+ || capability == NET_CAPABILITY_ENTERPRISE) {
assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
} else {
assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
@@ -2882,6 +2888,7 @@ public class ConnectivityServiceTest {
tryNetworkFactoryRequests(NET_CAPABILITY_IA);
tryNetworkFactoryRequests(NET_CAPABILITY_RCS);
tryNetworkFactoryRequests(NET_CAPABILITY_XCAP);
+ tryNetworkFactoryRequests(NET_CAPABILITY_ENTERPRISE);
tryNetworkFactoryRequests(NET_CAPABILITY_EIMS);
tryNetworkFactoryRequests(NET_CAPABILITY_NOT_METERED);
tryNetworkFactoryRequests(NET_CAPABILITY_INTERNET);
@@ -6847,7 +6854,7 @@ public class ConnectivityServiceTest {
callback.expectCapabilitiesThat(mMockVpn, (caps)
-> caps.getUids().size() == 2
&& caps.getUids().contains(new UidRange(uid, uid))
- && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER))
+ && caps.getUids().contains(createUidRange(RESTRICTED_USER))
&& caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_WIFI));
@@ -6857,7 +6864,7 @@ public class ConnectivityServiceTest {
callback.expectCapabilitiesThat(mMockVpn, (caps)
-> caps.getUids().size() == 2
&& caps.getUids().contains(new UidRange(uid, uid))
- && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER))
+ && caps.getUids().contains(createUidRange(RESTRICTED_USER))
&& caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_WIFI));
@@ -7491,7 +7498,7 @@ public class ConnectivityServiceTest {
assertNotNull(underlying);
mMockVpn.setVpnType(VpnManager.TYPE_VPN_LEGACY);
// The legacy lockdown VPN only supports userId 0.
- final Set<UidRange> ranges = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
+ final Set<UidRange> ranges = Collections.singleton(createUidRange(PRIMARY_USER));
mMockVpn.registerAgent(ranges);
mMockVpn.setUnderlyingNetworks(new Network[]{underlying});
mMockVpn.connect(true);
@@ -8410,7 +8417,7 @@ public class ConnectivityServiceTest {
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
mMockVpn.establish(lp, VPN_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
@@ -8438,7 +8445,7 @@ public class ConnectivityServiceTest {
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
@@ -8454,7 +8461,7 @@ public class ConnectivityServiceTest {
lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0"));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
@@ -8469,7 +8476,7 @@ public class ConnectivityServiceTest {
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
mMockVpn.establish(lp, VPN_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
@@ -8521,7 +8528,7 @@ public class ConnectivityServiceTest {
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
- final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER);
+ final UidRange vpnRange = createUidRange(PRIMARY_USER);
final Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
mMockVpn.establish(lp, VPN_UID, vpnRanges);
assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -8720,7 +8727,7 @@ public class ConnectivityServiceTest {
private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
throws Exception {
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
mMockVpn.setVpnType(vpnType);
mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
@@ -9279,7 +9286,7 @@ public class ConnectivityServiceTest {
lp.setInterfaceName("tun0");
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER);
+ final UidRange vpnRange = createUidRange(PRIMARY_USER);
Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
mMockVpn.establish(lp, VPN_UID, vpnRanges);
assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -10338,4 +10345,8 @@ public class ConnectivityServiceTest {
mEthernetNetworkAgent.getNetwork().netId, 0 /* times */,
true /* shouldDestroyNetwork */);
}
+
+ private UidRange createUidRange(int userId) {
+ return UidRange.createForUser(UserHandle.of(userId));
+ }
}
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index c86224a71978..32c95f149979 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -16,12 +16,16 @@
package com.android.server;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.INetd.IF_STATE_DOWN;
+import static android.net.INetd.IF_STATE_UP;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
@@ -36,6 +40,7 @@ import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.InetAddresses;
+import android.net.InterfaceConfigurationParcel;
import android.net.IpSecAlgorithm;
import android.net.IpSecConfig;
import android.net.IpSecManager;
@@ -48,7 +53,6 @@ import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.os.Binder;
-import android.os.INetworkManagementService;
import android.os.ParcelFileDescriptor;
import android.system.Os;
import android.test.mock.MockContext;
@@ -148,10 +152,17 @@ public class IpSecServiceParameterizedTest {
}
throw new SecurityException("Unavailable permission requested");
}
+
+ @Override
+ public int checkCallingOrSelfPermission(String permission) {
+ if (android.Manifest.permission.NETWORK_STACK.equals(permission)) {
+ return PERMISSION_GRANTED;
+ }
+ throw new UnsupportedOperationException();
+ }
};
INetd mMockNetd;
- INetworkManagementService mNetworkManager;
PackageManager mMockPkgMgr;
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
IpSecService mIpSecService;
@@ -181,10 +192,9 @@ public class IpSecServiceParameterizedTest {
@Before
public void setUp() throws Exception {
mMockNetd = mock(INetd.class);
- mNetworkManager = mock(INetworkManagementService.class);
mMockPkgMgr = mock(PackageManager.class);
mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
- mIpSecService = new IpSecService(mMockContext, mNetworkManager, mMockIpSecSrvConfig);
+ mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
// Injecting mock netd
when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
@@ -644,7 +654,10 @@ public class IpSecServiceParameterizedTest {
}
private IpSecTunnelInterfaceResponse createAndValidateTunnel(
- String localAddr, String remoteAddr, String pkgName) {
+ String localAddr, String remoteAddr, String pkgName) throws Exception {
+ final InterfaceConfigurationParcel config = new InterfaceConfigurationParcel();
+ config.flags = new String[] {IF_STATE_DOWN};
+ when(mMockNetd.interfaceGetCfg(anyString())).thenReturn(config);
IpSecTunnelInterfaceResponse createTunnelResp =
mIpSecService.createTunnelInterface(
mSourceAddr, mDestinationAddr, fakeNetwork, new Binder(), pkgName);
@@ -674,7 +687,8 @@ public class IpSecServiceParameterizedTest {
anyInt(),
anyInt(),
anyInt());
- verify(mNetworkManager).setInterfaceUp(createTunnelResp.interfaceName);
+ verify(mMockNetd).interfaceSetCfg(argThat(
+ config -> Arrays.asList(config.flags).contains(IF_STATE_UP)));
}
@Test
diff --git a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
index 788e4efe097e..22a2c94fc194 100644
--- a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
@@ -31,7 +31,6 @@ import static org.mockito.Mockito.verify;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
-import android.os.INetworkManagementService;
import android.os.RemoteException;
import androidx.test.filters.SmallTest;
@@ -62,8 +61,7 @@ public class IpSecServiceRefcountedResourceTest {
public void setUp() throws Exception {
mMockContext = mock(Context.class);
mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
- mIpSecService = new IpSecService(
- mMockContext, mock(INetworkManagementService.class), mMockIpSecSrvConfig);
+ mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
}
private void assertResourceState(
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index 536e98327e1f..f97eabf6366d 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -42,7 +42,6 @@ import android.net.IpSecManager;
import android.net.IpSecSpiResponse;
import android.net.IpSecUdpEncapResponse;
import android.os.Binder;
-import android.os.INetworkManagementService;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.system.ErrnoException;
@@ -116,7 +115,6 @@ public class IpSecServiceTest {
}
Context mMockContext;
- INetworkManagementService mMockNetworkManager;
INetd mMockNetd;
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
IpSecService mIpSecService;
@@ -124,10 +122,9 @@ public class IpSecServiceTest {
@Before
public void setUp() throws Exception {
mMockContext = mock(Context.class);
- mMockNetworkManager = mock(INetworkManagementService.class);
mMockNetd = mock(INetd.class);
mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
- mIpSecService = new IpSecService(mMockContext, mMockNetworkManager, mMockIpSecSrvConfig);
+ mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
// Injecting mock netd
when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
@@ -135,7 +132,7 @@ public class IpSecServiceTest {
@Test
public void testIpSecServiceCreate() throws InterruptedException {
- IpSecService ipSecSrv = IpSecService.create(mMockContext, mMockNetworkManager);
+ IpSecService ipSecSrv = IpSecService.create(mMockContext);
assertNotNull(ipSecSrv);
}
@@ -608,7 +605,7 @@ public class IpSecServiceTest {
public void testOpenUdpEncapSocketTagsSocket() throws Exception {
IpSecService.UidFdTagger mockTagger = mock(IpSecService.UidFdTagger.class);
IpSecService testIpSecService = new IpSecService(
- mMockContext, mMockNetworkManager, mMockIpSecSrvConfig, mockTagger);
+ mMockContext, mMockIpSecSrvConfig, mockTagger);
IpSecUdpEncapResponse udpEncapResp =
testIpSecService.openUdpEncapsulationSocket(0, new Binder());
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 8f5ae97bc4c5..e4e24b464838 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -61,6 +61,7 @@ import android.content.pm.PackageManagerInternal;
import android.net.INetd;
import android.net.UidRange;
import android.os.Build;
+import android.os.SystemConfigManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.SparseIntArray;
@@ -114,6 +115,7 @@ public class PermissionMonitorTest {
@Mock private PackageManagerInternal mMockPmi;
@Mock private UserManager mUserManager;
@Mock private PermissionMonitor.Dependencies mDeps;
+ @Mock private SystemConfigManager mSystemConfigManager;
private PermissionMonitor mPermissionMonitor;
@@ -124,6 +126,11 @@ public class PermissionMonitorTest {
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
when(mUserManager.getUserHandles(eq(true))).thenReturn(
Arrays.asList(new UserHandle[] { MOCK_USER1, MOCK_USER2 }));
+ when(mContext.getSystemServiceName(SystemConfigManager.class))
+ .thenReturn(Context.SYSTEM_CONFIG_SERVICE);
+ when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE))
+ .thenReturn(mSystemConfigManager);
+ when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
@@ -747,4 +754,20 @@ public class PermissionMonitorTest {
GET_PERMISSIONS | MATCH_ANY_USER);
assertTrue(monitor.hasPermission(systemInfo, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
}
+
+ @Test
+ public void testUpdateUidPermissionsFromSystemConfig() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(new ArrayList<>());
+ when(mSystemConfigManager.getSystemPermissionUids(eq(INTERNET)))
+ .thenReturn(new int[]{ MOCK_UID1, MOCK_UID2 });
+ when(mSystemConfigManager.getSystemPermissionUids(eq(UPDATE_DEVICE_STATS)))
+ .thenReturn(new int[]{ MOCK_UID2 });
+
+ mPermissionMonitor.startMonitoring();
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{ MOCK_UID1 });
+ mNetdServiceMonitor.expectPermission(
+ INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ new int[]{ MOCK_UID2 });
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index cffd2d1d428f..7489a0f889dc 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -21,6 +21,8 @@ import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
import static android.content.pm.UserInfo.FLAG_PRIMARY;
import static android.content.pm.UserInfo.FLAG_RESTRICTED;
import static android.net.ConnectivityManager.NetworkCallback;
+import static android.net.INetd.IF_STATE_DOWN;
+import static android.net.INetd.IF_STATE_UP;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -62,6 +64,7 @@ import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.Ikev2VpnProfile;
import android.net.InetAddresses;
+import android.net.InterfaceConfigurationParcel;
import android.net.IpPrefix;
import android.net.IpSecManager;
import android.net.IpSecTunnelInterfaceResponse;
@@ -179,7 +182,8 @@ public class VpnTest {
mPackages.put(PKGS[i], PKG_UIDS[i]);
}
}
- private static final UidRange PRI_USER_RANGE = UidRange.createForUser(primaryUser.id);
+ private static final UidRange PRI_USER_RANGE =
+ UidRange.createForUser(UserHandle.of(primaryUser.id));
@Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
@Mock private UserManager mUserManager;
@@ -269,7 +273,7 @@ public class VpnTest {
vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null);
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
- PRI_USER_RANGE, UidRange.createForUser(restrictedProfileA.id)
+ PRI_USER_RANGE, UidRange.createForUser(UserHandle.of(restrictedProfileA.id))
})), ranges);
}
@@ -872,17 +876,28 @@ public class VpnTest {
eq(AppOpsManager.MODE_IGNORED));
}
- private NetworkCallback triggerOnAvailableAndGetCallback() {
+ private NetworkCallback triggerOnAvailableAndGetCallback() throws Exception {
final ArgumentCaptor<NetworkCallback> networkCallbackCaptor =
ArgumentCaptor.forClass(NetworkCallback.class);
verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS))
.requestNetwork(any(), networkCallbackCaptor.capture());
+ // onAvailable() will trigger onDefaultNetworkChanged(), so NetdUtils#setInterfaceUp will be
+ // invoked. Set the return value of INetd#interfaceGetCfg to prevent NullPointerException.
+ final InterfaceConfigurationParcel config = new InterfaceConfigurationParcel();
+ config.flags = new String[] {IF_STATE_DOWN};
+ when(mNetd.interfaceGetCfg(anyString())).thenReturn(config);
final NetworkCallback cb = networkCallbackCaptor.getValue();
cb.onAvailable(TEST_NETWORK);
return cb;
}
+ private void verifyInterfaceSetCfgWithFlags(String flag) throws Exception {
+ // Add a timeout for waiting for interfaceSetCfg to be called.
+ verify(mNetd, timeout(TEST_TIMEOUT_MS)).interfaceSetCfg(argThat(
+ config -> Arrays.asList(config.flags).contains(flag)));
+ }
+
@Test
public void testStartPlatformVpnAuthenticationFailed() throws Exception {
final ArgumentCaptor<IkeSessionCallback> captor =
@@ -894,6 +909,8 @@ public class VpnTest {
final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), (mVpnProfile));
final NetworkCallback cb = triggerOnAvailableAndGetCallback();
+ verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
+
// Wait for createIkeSession() to be called before proceeding in order to ensure consistent
// state
verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS))
@@ -912,6 +929,8 @@ public class VpnTest {
final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
final NetworkCallback cb = triggerOnAvailableAndGetCallback();
+ verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
+
// Wait for createIkeSession() to be called before proceeding in order to ensure consistent
// state
verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
index 708767605508..66590c92579b 100644
--- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -16,6 +16,8 @@
package android.net.vcn;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
+
import static androidx.test.InstrumentationRegistry.getContext;
import static org.junit.Assert.assertEquals;
@@ -204,10 +206,13 @@ public class VcnManagerTest {
cbBinder.onEnteredSafeMode();
verify(mMockStatusCallback).onEnteredSafeMode();
+ cbBinder.onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE);
+ verify(mMockStatusCallback).onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE);
+
cbBinder.onGatewayConnectionError(
UNDERLYING_NETWORK_CAPABILITIES,
VcnManager.VCN_ERROR_CODE_NETWORK_ERROR,
- "java.net.UnknownHostException",
+ UnknownHostException.class.getName(),
"exception_message");
verify(mMockStatusCallback)
.onGatewayConnectionError(
diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
index 3ba0a1f53a9f..a674425efea3 100644
--- a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
@@ -46,6 +46,6 @@ public class VcnUnderlyingNetworkPolicyTest {
@Test
public void testParcelUnparcel() {
- assertParcelSane(SAMPLE_NETWORK_POLICY, 2);
+ assertParcelSane(SAMPLE_NETWORK_POLICY, 1);
}
}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 45b2381ce06d..9b500a7271d7 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -43,7 +43,6 @@ import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -59,6 +58,7 @@ import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
import android.net.vcn.VcnConfigTest;
+import android.net.vcn.VcnManager;
import android.net.vcn.VcnUnderlyingNetworkPolicy;
import android.net.wifi.WifiInfo;
import android.os.IBinder;
@@ -783,7 +783,7 @@ public class VcnManagementServiceTest {
true /* hasPermissionsforSubGroup */,
true /* hasLocationPermission */);
- verify(mMockStatusCallback, times(1)).onEnteredSafeMode();
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
}
@Test
@@ -795,7 +795,8 @@ public class VcnManagementServiceTest {
false /* hasPermissionsforSubGroup */,
true /* hasLocationPermission */);
- verify(mMockStatusCallback, never()).onEnteredSafeMode();
+ verify(mMockStatusCallback, never())
+ .onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
}
@Test
@@ -807,7 +808,8 @@ public class VcnManagementServiceTest {
true /* hasPermissionsforSubGroup */,
false /* hasLocationPermission */);
- verify(mMockStatusCallback, never()).onEnteredSafeMode();
+ verify(mMockStatusCallback, never())
+ .onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
}
@Test
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index f0b759547a93..ebc0ec1640f5 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -11,6 +11,12 @@ from fontTools import ttLib
EMOJI_VS = 0xFE0F
+#TODO(179952916): Rename CutiveMono and DancingScript
+CANONICAL_NAME_EXCEPTION_LIST = [
+ 'CutiveMono.ttf',
+ 'DancingScript-Regular.ttf',
+]
+
LANG_TO_SCRIPT = {
'as': 'Beng',
'be': 'Cyrl',
@@ -665,6 +671,53 @@ def check_cjk_punctuation():
assert_font_supports_none_of_chars(record.font, cjk_punctuation, name)
+def getPostScriptName(font):
+ ttf = open_font(font)
+ nameTable = ttf['name']
+ for name in nameTable.names:
+ if name.nameID == 6 and name.platformID == 3 and name.platEncID == 1 and name.langID == 0x0409:
+ return str(name)
+
+
+def getSuffix(font):
+ file_path, index = font
+ with open(path.join(_fonts_dir, file_path), 'rb') as f:
+ tag = f.read(4)
+ isCollection = tag == b'ttcf'
+
+ ttf = open_font(font)
+ isType1 = ('CFF ' in ttf or 'CFF2' in ttf)
+
+ if isType1:
+ if isCollection:
+ return '.otc'
+ else:
+ return '.otf'
+ else:
+ if isCollection:
+ return '.ttc'
+ else:
+ return '.ttf'
+
+
+def check_canonical_name():
+ for record in _all_fonts:
+ file_name, index = record.font
+ if file_name in CANONICAL_NAME_EXCEPTION_LIST:
+ continue
+
+ if index and index != 0:
+ continue
+
+ psName = getPostScriptName(record.font)
+ assert psName, 'PostScript must be defined'
+
+ suffix = getSuffix(record.font)
+ canonicalName = '%s%s' % (psName, suffix)
+
+ assert file_name == canonicalName, (
+ '%s is not a canonical name. Must be %s' % (file_name, canonicalName))
+
def main():
global _fonts_dir
target_out = sys.argv[1]
@@ -682,6 +735,8 @@ def main():
check_cjk_punctuation()
+ check_canonical_name()
+
check_emoji = sys.argv[2]
if check_emoji == 'true':
ucd_path = sys.argv[3]
diff --git a/tools/powerstats/Android.bp b/tools/powerstats/Android.bp
index af41144167a9..9c58daf0f922 100644
--- a/tools/powerstats/Android.bp
+++ b/tools/powerstats/Android.bp
@@ -1,3 +1,12 @@
+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_binary_host {
name: "PowerStatsServiceProtoParser",
manifest: "PowerStatsServiceProtoParser_manifest.txt",
diff --git a/tools/processors/intdef_mappings/Android.bp b/tools/processors/intdef_mappings/Android.bp
index e255f7c784d3..82a5dac21160 100644
--- a/tools/processors/intdef_mappings/Android.bp
+++ b/tools/processors/intdef_mappings/Android.bp
@@ -1,3 +1,12 @@
+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_plugin {
name: "intdef-annotation-processor",
@@ -30,4 +39,4 @@ java_test_host {
],
test_suites: ["general-tests"],
-} \ No newline at end of file
+}
diff --git a/tools/xmlpersistence/Android.bp b/tools/xmlpersistence/Android.bp
index d58d0dcdc45a..0b6dba626794 100644
--- a/tools/xmlpersistence/Android.bp
+++ b/tools/xmlpersistence/Android.bp
@@ -1,3 +1,12 @@
+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_binary_host {
name: "xmlpersistence_cli",
manifest: "manifest.txt",