summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PREUPLOAD.cfg1
-rw-r--r--StubLibraries.bp50
-rw-r--r--apct-tests/perftests/multiuser/AndroidTest.xml3
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java43
-rw-r--r--apct-tests/perftests/windowmanager/AndroidManifest.xml4
-rw-r--r--apct-tests/perftests/windowmanager/AndroidTest.xml4
-rw-r--r--apct-tests/perftests/windowmanager/README.md8
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java40
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java20
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java18
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java6
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java36
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java29
-rw-r--r--apex/jobscheduler/service/java/com/android/server/JobSchedulerBackgroundThread.java13
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java4
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java404
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java2
-rw-r--r--api/current.txt20
-rwxr-xr-xapi/system-current.txt17
-rw-r--r--api/test-current.txt8
-rw-r--r--cmds/incidentd/src/IncidentService.cpp4
-rw-r--r--cmds/statsd/src/atoms.proto54
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.cpp29
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.h2
-rw-r--r--cmds/statsd/src/condition/ConditionTracker.h8
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.cpp9
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.h2
-rw-r--r--cmds/statsd/src/matchers/AtomMatchingTracker.h11
-rw-r--r--cmds/statsd/src/matchers/CombinationAtomMatchingTracker.cpp17
-rw-r--r--cmds/statsd/src/matchers/CombinationAtomMatchingTracker.h7
-rw-r--r--cmds/statsd/src/matchers/SimpleAtomMatchingTracker.cpp8
-rw-r--r--cmds/statsd/src/matchers/SimpleAtomMatchingTracker.h5
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp9
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp3
-rw-r--r--cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp30
-rw-r--r--cmds/uinput/Android.bp18
-rw-r--r--cmds/uinput/MODULE_LICENSE_APACHE20
-rw-r--r--cmds/uinput/NOTICE190
-rw-r--r--cmds/uinput/README.md166
-rw-r--r--cmds/uinput/jni/Android.bp23
-rw-r--r--cmds/uinput/jni/com_android_commands_uinput_Device.cpp351
-rw-r--r--cmds/uinput/jni/com_android_commands_uinput_Device.h67
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/Device.java232
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/Event.java454
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/InputAbsInfo.aidl26
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/Uinput.java140
-rwxr-xr-xcmds/uinput/uinput9
-rw-r--r--config/Android.bp4
-rwxr-xr-xconfig/generate-preloaded-classes.sh6
-rw-r--r--config/preloaded-classes-denylist (renamed from config/preloaded-classes-blacklist)0
-rw-r--r--core/java/android/app/ActivityThread.java22
-rw-r--r--core/java/android/app/AppOpsManager.java46
-rw-r--r--core/java/android/app/ApplicationPackageManager.java3
-rw-r--r--core/java/android/app/ContextImpl.java71
-rw-r--r--core/java/android/app/IActivityManager.aidl3
-rw-r--r--core/java/android/app/LoadedApk.java5
-rw-r--r--core/java/android/app/ResourcesManager.java438
-rw-r--r--core/java/android/app/WindowTokenClient.java3
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java46
-rw-r--r--core/java/android/content/pm/PackageInstaller.java8
-rw-r--r--core/java/android/content/pm/PackageParser.java3
-rw-r--r--core/java/android/content/res/ResourcesKey.java21
-rw-r--r--core/java/android/os/BatteryStats.java2
-rw-r--r--core/java/android/os/GraphicsEnvironment.java9
-rw-r--r--core/java/android/os/IPowerManager.aidl4
-rw-r--r--core/java/android/os/ParcelDuration.aidl19
-rw-r--r--core/java/android/os/ParcelDuration.java103
-rw-r--r--core/java/android/os/PowerManager.java77
-rw-r--r--core/java/android/os/Trace.java2
-rw-r--r--core/java/android/os/incremental/IIncrementalService.aidl5
-rw-r--r--core/java/android/os/incremental/IncrementalStorage.java28
-rw-r--r--core/java/android/preference/DialogPreference.java23
-rw-r--r--core/java/android/preference/EditTextPreference.java18
-rw-r--r--core/java/android/preference/OWNERS1
-rw-r--r--core/java/android/provider/DeviceConfig.java7
-rw-r--r--core/java/android/provider/Settings.java44
-rw-r--r--core/java/android/service/autofill/AutofillService.java14
-rw-r--r--core/java/android/speech/tts/TextToSpeech.java33
-rw-r--r--core/java/android/telephony/PhoneStateListener.java46
-rw-r--r--core/java/android/text/OWNERS3
-rw-r--r--core/java/android/view/InputEventReceiver.java14
-rw-r--r--core/java/android/view/InputWindowHandle.java7
-rw-r--r--core/java/android/view/InsetsController.java11
-rw-r--r--core/java/android/view/InsetsState.java2
-rw-r--r--core/java/android/view/ViewPropertyAnimator.java3
-rw-r--r--core/java/android/view/ViewRootImpl.java47
-rw-r--r--core/java/android/webkit/PacProcessor.java36
-rw-r--r--core/java/android/webkit/WebViewFactoryProvider.java9
-rw-r--r--core/java/android/window/ITaskOrganizerController.aidl6
-rw-r--r--core/java/android/window/TaskOrganizer.java8
-rw-r--r--core/java/android/window/TaskOrganizerTaskEmbedder.java2
-rw-r--r--core/java/com/android/internal/os/TEST_MAPPING15
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java2
-rw-r--r--core/java/com/android/internal/telephony/IPhoneStateListener.aidl2
-rw-r--r--core/java/com/android/internal/util/Preconditions.java14
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl3
-rw-r--r--core/java/com/android/internal/widget/LocalImageResolver.java17
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java35
-rw-r--r--core/java/com/android/internal/widget/VerifyCredentialResponse.java37
-rw-r--r--core/jni/android_hardware_input_InputWindowHandle.cpp14
-rw-r--r--core/jni/android_os_HwRemoteBinder.cpp19
-rw-r--r--core/jni/android_os_HwRemoteBinder.h13
-rw-r--r--core/jni/android_view_InputEventReceiver.cpp118
-rw-r--r--core/proto/android/app/settings_enums.proto10
-rw-r--r--core/proto/android/providers/settings/global.proto2
-rw-r--r--core/proto/android/server/powermanagerservice.proto10
-rw-r--r--core/res/Android.bp7
-rw-r--r--core/res/AndroidManifest.xml5
-rw-r--r--core/res/res/values-ar/strings.xml6
-rw-r--r--core/res/res/values-in/strings.xml2
-rw-r--r--core/res/res/values-mk/strings.xml2
-rw-r--r--core/tests/coretests/src/android/app/activity/ActivityThreadTest.java49
-rw-r--r--core/tests/coretests/src/android/content/res/ResourcesManagerTest.java111
-rw-r--r--core/tests/coretests/src/android/text/OWNERS3
-rw-r--r--core/tests/coretests/src/android/view/InsetsControllerTest.java14
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java1
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk4
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk2
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk2
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk2
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk2
-rw-r--r--data/etc/car/Android.bp7
-rw-r--r--data/etc/car/com.android.car.floatingcardslauncher.xml25
-rw-r--r--graphics/java/android/graphics/Bitmap.java4
-rw-r--r--graphics/java/android/graphics/BlurShader.java65
-rw-r--r--keystore/TEST_MAPPING74
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java161
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java30
-rw-r--r--libs/WindowManager/Shell/tests/README.md15
-rw-r--r--libs/WindowManager/Shell/tests/flicker/Android.bp34
-rw-r--r--libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml43
-rw-r--r--libs/WindowManager/Shell/tests/flicker/AndroidTest.xml40
-rw-r--r--libs/WindowManager/Shell/tests/flicker/README.md10
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt153
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt130
-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/helpers/FlickerAppHelper.kt (renamed from packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManager.java)37
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt45
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt121
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt (renamed from packages/SystemUI/src/com/android/systemui/onehanded/dagger/OneHandedModule.java)27
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/Android.bp0
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp20
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml37
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml26
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java45
-rw-r--r--libs/WindowManager/Shell/tests/unittest/Android.bp (renamed from libs/WindowManager/Shell/tests/Android.bp)2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml (renamed from libs/WindowManager/Shell/tests/AndroidManifest.xml)0
-rw-r--r--libs/WindowManager/Shell/tests/unittest/AndroidTest.xml (renamed from libs/WindowManager/Shell/tests/AndroidTest.xml)4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/res/values/config.xml (renamed from libs/WindowManager/Shell/tests/res/values/config.xml)0
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java121
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java (renamed from libs/WindowManager/Shell/tests/src/com/android/wm/shell/common/DisplayLayoutTest.java)0
-rw-r--r--libs/androidfw/ResourceTypes.cpp1
-rw-r--r--libs/hwui/Android.bp1
-rw-r--r--libs/hwui/HardwareBitmapUploader.cpp98
-rw-r--r--libs/hwui/RecordingCanvas.cpp1
-rw-r--r--libs/hwui/jni/Picture.cpp2
-rw-r--r--libs/hwui/jni/Shader.cpp23
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp4
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp4
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp21
-rw-r--r--libs/hwui/renderthread/RenderThread.h4
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp43
-rw-r--r--libs/hwui/renderthread/VulkanManager.h24
-rw-r--r--libs/hwui/shader/BlurShader.cpp38
-rw-r--r--libs/hwui/shader/BlurShader.h42
-rw-r--r--libs/hwui/shader/Shader.h4
-rw-r--r--libs/hwui/tests/unit/SkiaCanvasTests.cpp4
-rw-r--r--libs/input/MouseCursorController.cpp51
-rw-r--r--libs/input/MouseCursorController.h11
-rw-r--r--libs/input/PointerController.cpp24
-rw-r--r--libs/input/PointerController.h1
-rw-r--r--libs/input/PointerControllerContext.cpp135
-rw-r--r--libs/input/PointerControllerContext.h43
-rw-r--r--libs/input/TouchSpotController.cpp36
-rw-r--r--libs/input/TouchSpotController.h8
-rw-r--r--location/java/android/location/timezone/LocationTimeZoneEvent.java54
-rw-r--r--location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java2
-rw-r--r--location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java18
-rw-r--r--media/java/android/media/MediaTranscodeManager.java195
-rw-r--r--media/java/android/media/session/MediaSession.java2
-rw-r--r--media/jni/android_media_tv_Tuner.cpp4
-rw-r--r--media/tests/MediaTranscodingTest/Android.bp1
-rw-r--r--media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java103
-rw-r--r--non-updatable-api/current.txt18
-rw-r--r--non-updatable-api/system-current.txt17
-rw-r--r--packages/CarSystemUI/res/values/config.xml1
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml3
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java14
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java33
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java31
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java4
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java4
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java18
-rw-r--r--packages/PrintSpooler/res/values-fa/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-uz/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml10
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java3
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/SystemUI/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/README.md9
-rw-r--r--packages/SystemUI/proguard.flags3
-rw-r--r--packages/SystemUI/res-keyguard/drawable/face_auth_wallpaper.pngbin0 -> 709067 bytes
-rw-r--r--packages/SystemUI/res/layout/bubble_stack_user_education.xml15
-rw-r--r--packages/SystemUI/res/layout/bubbles_manage_button_education.xml124
-rw-r--r--packages/SystemUI/res/layout/notification_conversation_info.xml2
-rw-r--r--packages/SystemUI/res/layout/partial_conversation_info.xml1
-rw-r--r--packages/SystemUI/res/values-af/strings.xml2
-rw-r--r--packages/SystemUI/res/values-am/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml2
-rw-r--r--packages/SystemUI/res/values-as/strings.xml2
-rw-r--r--packages/SystemUI/res/values-az/strings.xml2
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-be/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml2
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml2
-rw-r--r--packages/SystemUI/res/values-da/strings.xml2
-rw-r--r--packages/SystemUI/res/values-de/strings.xml2
-rw-r--r--packages/SystemUI/res/values-el/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml2
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml2
-rw-r--r--packages/SystemUI/res/values-es/strings.xml2
-rw-r--r--packages/SystemUI/res/values-et/strings.xml2
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml4
-rw-r--r--packages/SystemUI/res/values-in/strings.xml2
-rw-r--r--packages/SystemUI/res/values-is/strings.xml2
-rw-r--r--packages/SystemUI/res/values-it/strings.xml2
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml2
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-km/strings.xml2
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml2
-rw-r--r--packages/SystemUI/res/values-my/strings.xml2
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml2
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml4
-rw-r--r--packages/SystemUI/res/values-or/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml2
-rw-r--r--packages/SystemUI/res/values-si/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml4
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml2
-rw-r--r--packages/SystemUI/res/values-te/strings.xml2
-rw-r--r--packages/SystemUI/res/values-television/config.xml2
-rw-r--r--packages/SystemUI/res/values-th/strings.xml2
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml2
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml4
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml2
-rw-r--r--packages/SystemUI/res/values/config.xml2
-rw-r--r--packages/SystemUI/res/values/dimens.xml2
-rw-r--r--packages/SystemUI/res/values/strings.xml4
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/ExpandHelper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java283
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt98
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt134
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeService.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt193
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt65
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedController.java (renamed from packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java)8
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java65
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java69
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java157
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java (renamed from packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java)67
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java87
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt (renamed from libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java)27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSection.java)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java578
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java393
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java120
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java76
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/DeviceConfigProxy.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java111
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java18
-rw-r--r--packages/SystemUI/tests/AndroidManifest.xml2
-rw-r--r--packages/SystemUI/tests/res/values/strings.xml21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt135
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedControllerTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java)16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureTest.java101
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollViewActivity.java42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java128
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java126
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java206
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFakeTest.java100
-rw-r--r--services/Android.bp4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java18
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java50
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java15
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java2
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java72
-rw-r--r--services/core/java/com/android/server/Watchdog.java1
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java11
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java13
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java36
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java2
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java8
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java7
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java6
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java150
-rw-r--r--services/core/java/com/android/server/connectivity/PermissionMonitor.java260
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java17
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java2
-rw-r--r--services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java4
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java114
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java13
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java3
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java69
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java122
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java16
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java114
-rw-r--r--services/core/java/com/android/server/pm/Settings.java109
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java2
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java128
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java110
-rw-r--r--services/core/java/com/android/server/pm/permission/BasePermission.java4
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java362
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java47
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java14
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java246
-rw-r--r--services/core/java/com/android/server/power/Notifier.java15
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java154
-rw-r--r--services/core/java/com/android/server/storage/StorageSessionController.java5
-rw-r--r--services/core/java/com/android/server/uri/UriGrantsManagerService.java17
-rw-r--r--services/core/java/com/android/server/webkit/WebViewUpdateService.java4
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java12
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java92
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/BarController.java8
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java26
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java83
-rw-r--r--services/core/java/com/android/server/wm/DragState.java5
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java2
-rw-r--r--services/core/java/com/android/server/wm/InputConsumerImpl.java3
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java39
-rw-r--r--services/core/java/com/android/server/wm/InsetsControlTarget.java8
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java10
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java6
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java2
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java59
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java7
-rw-r--r--services/core/java/com/android/server/wm/Task.java52
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java6
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java120
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java4
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java2
-rw-r--r--services/core/java/com/android/server/wm/UnknownAppVisibilityController.java10
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java33
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java212
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java88
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java948
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java324
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java121
-rw-r--r--services/incremental/BinderIncrementalService.cpp8
-rw-r--r--services/incremental/BinderIncrementalService.h3
-rw-r--r--services/incremental/IncrementalService.cpp51
-rw-r--r--services/incremental/IncrementalService.h7
-rw-r--r--services/incremental/ServiceWrappers.cpp45
-rw-r--r--services/incremental/ServiceWrappers.h13
-rw-r--r--services/incremental/test/IncrementalServiceTest.cpp197
-rw-r--r--services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java4
-rw-r--r--services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java27
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java36
-rw-r--r--services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java70
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt4
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt10
-rw-r--r--services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java49
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java176
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java13
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java28
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java63
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java82
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java96
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java7
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java4
-rw-r--r--startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java2
-rw-r--r--telephony/api/system-current.txt7
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java2
-rw-r--r--telephony/java/android/telephony/CellIdentityNr.java12
-rw-r--r--telephony/java/android/telephony/CellInfoNr.java14
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java75
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl4
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml9
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java110
-rw-r--r--tests/StagedInstallTest/Android.bp3
-rw-r--r--tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java4
-rw-r--r--tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java69
-rw-r--r--tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java2
-rw-r--r--tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java2
-rw-r--r--tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java391
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java56
-rw-r--r--tools/preload-check/Android.bp2
-rw-r--r--tools/preload-check/src/com/android/preload/check/PreloadCheck.java6
-rw-r--r--wifi/api/current.txt2
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSuggestion.java50
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java35
563 files changed, 12578 insertions, 6176 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 2fd2e33bbc37..fc5efc6e03ac 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -6,6 +6,7 @@ clang_format = true
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
cmds/hid/
cmds/input/
+ cmds/uinput/
core/jni/
libs/input/
services/core/jni/
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 2bd5aee0cd24..bb6538739c49 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -299,6 +299,7 @@ java_defaults {
static_libs: [
// License notices from art module
"art-notices-for-framework-stubs-jar",
+ "framework-res-package-jar", // Export package of framework-res
],
errorprone: {
javacflags: [
@@ -311,6 +312,15 @@ java_defaults {
compile_dex: true,
}
+java_defaults {
+ name: "android_stubs_dists_default",
+ dist: {
+ targets: ["sdk", "win_sdk"],
+ tag: ".jar",
+ dest: "android.jar",
+ },
+}
+
java_library_static {
name: "android_monolith_stubs_current",
srcs: [ ":api-stubs-docs" ],
@@ -346,7 +356,21 @@ java_library_static {
name: "android_system_monolith_stubs_current",
srcs: [ ":system-api-stubs-docs" ],
static_libs: [ "private-stub-annotations-jar" ],
- defaults: ["android_defaults_stubs_current"],
+ defaults: [
+ "android_defaults_stubs_current",
+ "android_stubs_dists_default",
+ ],
+ dist: {
+ dir: "apistubs/android/system",
+ },
+ dists: [
+ {
+ // Legacy dist path
+ targets: ["sdk", "win_sdk"],
+ tag: ".jar",
+ dest: "android_system.jar",
+ },
+ ],
}
java_library_static {
@@ -378,14 +402,34 @@ java_library_static {
name: "android_test_stubs_current",
srcs: [ ":test-api-stubs-docs" ],
static_libs: [ "private-stub-annotations-jar" ],
- defaults: ["android_defaults_stubs_current"],
+ defaults: [
+ "android_defaults_stubs_current",
+ "android_stubs_dists_default",
+ ],
+ dist: {
+ dir: "apistubs/android/test",
+ },
+ dists: [
+ {
+ // Legacy dist path
+ targets: ["sdk", "win_sdk"],
+ tag: ".jar",
+ dest: "android_test.jar",
+ },
+ ],
}
java_library_static {
name: "android_module_lib_stubs_current",
srcs: [ ":module-lib-api-stubs-docs-non-updatable" ],
- defaults: ["android_defaults_stubs_current"],
+ defaults: [
+ "android_defaults_stubs_current",
+ "android_stubs_dists_default",
+ ],
libs: ["sdk_system_29_android"],
+ dist: {
+ dir: "apistubs/android/module-lib",
+ },
}
java_library_static {
diff --git a/apct-tests/perftests/multiuser/AndroidTest.xml b/apct-tests/perftests/multiuser/AndroidTest.xml
index c7929af6077f..fbe589248338 100644
--- a/apct-tests/perftests/multiuser/AndroidTest.xml
+++ b/apct-tests/perftests/multiuser/AndroidTest.xml
@@ -27,6 +27,9 @@
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+ <!--Install the content provider automatically when we push some file in sdcard folder.-->
+ <!--Needed to avoid the installation during the test suite.-->
+ <option name="push-file" key="trace_config_detailed.textproto" value="/sdcard/sample.textproto" />
</target_preparer>
<!-- Needed for pulling the collected trace config on to the host -->
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
index 93bf541d02b4..e1928615211a 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
@@ -53,7 +53,8 @@ public final class BenchmarkState {
private static final int NOT_STARTED = 0; // The benchmark has not started yet.
private static final int WARMUP = 1; // The benchmark is warming up.
private static final int RUNNING = 2; // The benchmark is running.
- private static final int FINISHED = 3; // The benchmark has stopped.
+ private static final int RUNNING_CUSTOMIZED = 3; // Running for customized measurement.
+ private static final int FINISHED = 4; // The benchmark has stopped.
private int mState = NOT_STARTED; // Current benchmark state.
@@ -76,6 +77,14 @@ public final class BenchmarkState {
private int mRepeatCount = 0;
+ /**
+ * Additional iteration that used to apply customized measurement. The result during these
+ * iterations won't be counted into {@link #mStats}.
+ */
+ private int mMaxCustomizedIterations;
+ private int mCustomizedIterations;
+ private CustomizedIterationListener mCustomizedIterationListener;
+
// Statistics. These values will be filled when the benchmark has finished.
// The computation needs double precision, but long int is fine for final reporting.
private Stats mStats;
@@ -110,6 +119,15 @@ public final class BenchmarkState {
mPaused = false;
}
+ /**
+ * This is used to run the benchmark with more information by enabling some debug mechanism but
+ * we don't want to account the special runs (slower) in the stats report.
+ */
+ public void setCustomizedIterations(int iterations, CustomizedIterationListener listener) {
+ mMaxCustomizedIterations = iterations;
+ mCustomizedIterationListener = listener;
+ }
+
private void beginWarmup() {
mStartTimeNs = System.nanoTime();
mIteration = 0;
@@ -141,6 +159,11 @@ public final class BenchmarkState {
Debug.stopMethodTracing();
}
mStats = new Stats(mResults);
+ if (mMaxCustomizedIterations > 0 && mCustomizedIterationListener != null) {
+ mState = RUNNING_CUSTOMIZED;
+ mCustomizedIterationListener.onStart(mCustomizedIterations);
+ return true;
+ }
mState = FINISHED;
return false;
}
@@ -180,6 +203,15 @@ public final class BenchmarkState {
"Resume the benchmark before finishing each step.");
}
return true;
+ case RUNNING_CUSTOMIZED:
+ mCustomizedIterationListener.onFinished(mCustomizedIterations);
+ mCustomizedIterations++;
+ if (mCustomizedIterations >= mMaxCustomizedIterations) {
+ mState = FINISHED;
+ return false;
+ }
+ mCustomizedIterationListener.onStart(mCustomizedIterations);
+ return true;
case FINISHED:
throw new IllegalStateException("The benchmark has finished.");
default:
@@ -240,4 +272,13 @@ public final class BenchmarkState {
status.putLong(key + "_standardDeviation", standardDeviation());
instrumentation.sendStatus(Activity.RESULT_OK, status);
}
+
+ /** The interface to receive the events of customized iteration. */
+ public interface CustomizedIterationListener {
+ /** The customized iteration starts. */
+ void onStart(int iteration);
+
+ /** The customized iteration finished. */
+ void onFinished(int iteration);
+ }
}
diff --git a/apct-tests/perftests/windowmanager/AndroidManifest.xml b/apct-tests/perftests/windowmanager/AndroidManifest.xml
index 85fd7176c33a..95ede345fbee 100644
--- a/apct-tests/perftests/windowmanager/AndroidManifest.xml
+++ b/apct-tests/perftests/windowmanager/AndroidManifest.xml
@@ -29,5 +29,7 @@
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.perftests.wm"/>
+ android:targetPackage="com.android.perftests.wm">
+ <meta-data android:name="listener" android:value="android.wm.WmPerfRunListener" />
+ </instrumentation>
</manifest>
diff --git a/apct-tests/perftests/windowmanager/AndroidTest.xml b/apct-tests/perftests/windowmanager/AndroidTest.xml
index aee02c7ab767..6ac9f9373f8c 100644
--- a/apct-tests/perftests/windowmanager/AndroidTest.xml
+++ b/apct-tests/perftests/windowmanager/AndroidTest.xml
@@ -42,7 +42,7 @@
<option name="hidden-api-checks" value="false"/>
<!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
- <option name="device-listeners" value="android.wm.WmPerfRunListener,android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+ <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
<!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
<option name="instrumentation-arg" key="newRunListenerMode" value="true" />
@@ -57,8 +57,6 @@
<!-- PerfettoListener related arguments -->
<option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
<option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
-
- <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
</test>
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
diff --git a/apct-tests/perftests/windowmanager/README.md b/apct-tests/perftests/windowmanager/README.md
index 05fa6279a949..8b5292fd02a5 100644
--- a/apct-tests/perftests/windowmanager/README.md
+++ b/apct-tests/perftests/windowmanager/README.md
@@ -25,3 +25,11 @@ adb shell am instrument -w -r -e class android.wm.RelayoutPerfTest \
com.android.perftests.wm/androidx.test.runner.AndroidJUnitRunner
```
* `kill-bg` is optional.
+
+Test arguments
+ - kill-bg
+ * boolean: Kill background process before running test.
+ - profiling-iterations
+ * int: Run the extra iterations with enabling method profiling.
+ - profiling-sampling
+ * int: The interval (0=trace each method, default is 10) of sample profiling in microseconds.
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
index 4ed3b4e09d11..5c09ec2e760f 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
@@ -41,7 +41,8 @@ import java.util.concurrent.TimeUnit;
/** Measure the performance of internal methods in window manager service by trace tag. */
@LargeTest
-public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase {
+public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase
+ implements ManualBenchmarkState.CustomizedIterationListener {
private static final String TAG = InternalWindowOperationPerfTest.class.getSimpleName();
@Rule
@@ -68,6 +69,9 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase {
"finishActivity",
"startActivityInner");
+ private boolean mIsProfiling;
+ private boolean mIsTraceStarted;
+
@Test
@ManualBenchmarkTest(
targetTestDurationNs = 20 * TIME_1_S_IN_NS,
@@ -76,13 +80,13 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase {
| StatsReport.FLAG_MAX | StatsReport.FLAG_COEFFICIENT_VAR))
public void testLaunchAndFinishActivity() throws Throwable {
final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ state.setCustomizedIterations(getProfilingIterations(), this);
long measuredTimeNs = 0;
- boolean isTraceStarted = false;
while (state.keepRunning(measuredTimeNs)) {
- if (!isTraceStarted && !state.isWarmingUp()) {
+ if (!mIsTraceStarted && !mIsProfiling && !state.isWarmingUp()) {
startAsyncAtrace();
- isTraceStarted = true;
+ mIsTraceStarted = true;
}
final long startTime = SystemClock.elapsedRealtimeNanos();
mActivityRule.launchActivity();
@@ -91,7 +95,9 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase {
measuredTimeNs = SystemClock.elapsedRealtimeNanos() - startTime;
}
- stopAsyncAtrace();
+ if (mIsTraceStarted) {
+ stopAsyncAtrace();
+ }
mTraceMarkParser.forAllSlices((key, slices) -> {
for (TraceMarkSlice slice : slices) {
@@ -108,7 +114,7 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase {
SystemClock.sleep(TimeUnit.NANOSECONDS.toMillis(TIME_1_S_IN_NS));
}
- private void stopAsyncAtrace() throws IOException {
+ private void stopAsyncAtrace() {
final ParcelFileDescriptor pfd = sUiAutomation.executeShellCommand("atrace --async_stop");
final InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
@@ -116,6 +122,28 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase {
while ((line = reader.readLine()) != null) {
mTraceMarkParser.visit(line);
}
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to read the result of stopped atrace", e);
+ }
+ }
+
+ @Override
+ public void onStart(int iteration) {
+ if (mIsTraceStarted) {
+ // Do not capture trace when profiling because the result will be much slower.
+ stopAsyncAtrace();
+ mIsTraceStarted = false;
+ }
+ mIsProfiling = true;
+ startProfiling(InternalWindowOperationPerfTest.class.getSimpleName()
+ + "_MethodTracing_" + iteration + ".trace");
+ }
+
+ @Override
+ public void onFinished(int iteration) {
+ stopProfiling();
+ if (iteration >= getProfilingIterations() - 1) {
+ mIsProfiling = false;
}
}
}
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
index 6122ef254855..efcabd817109 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
@@ -62,7 +62,8 @@ import java.util.concurrent.TimeUnit;
@RunWith(Parameterized.class)
@LargeTest
-public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase {
+public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase
+ implements ManualBenchmarkState.CustomizedIterationListener {
private static Intent sRecentsIntent;
@Rule
@@ -162,6 +163,7 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase {
| StatsReport.FLAG_COEFFICIENT_VAR))
public void testRecentsAnimation() throws Throwable {
final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ state.setCustomizedIterations(getProfilingIterations(), this);
final IActivityTaskManager atm = ActivityTaskManager.getService();
final ArrayList<Pair<String, Boolean>> finishCases = new ArrayList<>();
@@ -230,7 +232,21 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase {
state.addExtraResult("start", elapsedTimeNsOfStart);
// Ensure the animation callback is done.
- Assume.assumeTrue(recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS));
+ Assume.assumeTrue(recentsSemaphore.tryAcquire(
+ sIsProfilingMethod ? 10 * TIME_5_S_IN_NS : TIME_5_S_IN_NS,
+ TimeUnit.NANOSECONDS));
}
}
+
+ @Override
+ public void onStart(int iteration) {
+ startProfiling(RecentsAnimationPerfTest.class.getSimpleName()
+ + "_interval_" + intervalBetweenOperations
+ + "_MethodTracing_" + iteration + ".trace");
+ }
+
+ @Override
+ public void onFinished(int iteration) {
+ stopProfiling();
+ }
}
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
index cff5663e9d9e..269742854cb0 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
@@ -54,7 +54,8 @@ import java.util.function.IntSupplier;
@RunWith(Parameterized.class)
@LargeTest
@Presubmit
-public class RelayoutPerfTest extends WindowManagerPerfTestBase {
+public class RelayoutPerfTest extends WindowManagerPerfTestBase
+ implements BenchmarkState.CustomizedIterationListener {
private int mIteration;
@Rule
@@ -93,9 +94,22 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase {
mActivityRule.runOnUiThread(() -> activity.setContentView(contentView));
getInstrumentation().waitForIdleSync();
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ state.setCustomizedIterations(getProfilingIterations(), this);
final RelayoutRunner relayoutRunner = new RelayoutRunner(activity, contentView.getWindow(),
() -> visibilities[mIteration++ % visibilities.length]);
- relayoutRunner.runBenchmark(mPerfStatusReporter.getBenchmarkState());
+ relayoutRunner.runBenchmark(state);
+ }
+
+ @Override
+ public void onStart(int iteration) {
+ startProfiling(RelayoutPerfTest.class.getSimpleName() + "_" + testName
+ + "_MethodTracing_" + iteration + ".trace");
+ }
+
+ @Override
+ public void onFinished(int iteration) {
+ stopProfiling();
}
/** A dummy view to get IWindow. */
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
index c72cc9d635e0..c52b1300aedc 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
@@ -48,8 +48,6 @@ import org.junit.Test;
public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase
implements ManualBenchmarkState.CustomizedIterationListener {
- private static final int PROFILED_ITERATIONS = 2;
-
@Rule
public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
@@ -64,7 +62,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase
sUiAutomation.dropShellPermissionIdentity();
}
- /** The last {@link #PROFILED_ITERATIONS} will provide the information of method profiling. */
+ /** The last customized iterations will provide the information of method profiling. */
@Override
public void onStart(int iteration) {
startProfiling(WindowAddRemovePerfTest.class.getSimpleName()
@@ -80,7 +78,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase
@ManualBenchmarkTest(warmupDurationNs = TIME_1_S_IN_NS, targetTestDurationNs = TIME_5_S_IN_NS)
public void testAddRemoveWindow() throws Throwable {
final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- state.setCustomizedIterations(PROFILED_ITERATIONS, this);
+ state.setCustomizedIterations(getProfilingIterations(), this);
new TestWindow().runBenchmark(state);
}
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
index cc0e939a2a80..b51a9a8fb0dd 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
@@ -32,6 +32,7 @@ import androidx.test.runner.lifecycle.ActivityLifecycleCallback;
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
import androidx.test.runner.lifecycle.Stage;
+import org.junit.After;
import org.junit.BeforeClass;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
@@ -52,18 +53,17 @@ public class WindowManagerPerfTestBase {
/**
* The out directory matching the directory-keys of collector in AndroidTest.xml. The directory
- * is in /data because while enabling method profling of system server, it cannot write the
+ * is in /data because while enabling method profiling of system server, it cannot write the
* trace to external storage.
*/
static final File BASE_OUT_PATH = new File("/data/local/tmp/WmPerfTests");
+ static boolean sIsProfilingMethod;
+
@BeforeClass
public static void setUpOnce() {
final Context context = getInstrumentation().getContext();
- if (!BASE_OUT_PATH.exists()) {
- executeShellCommand("mkdir -p " + BASE_OUT_PATH);
- }
if (!context.getSystemService(PowerManager.class).isInteractive()
|| context.getSystemService(KeyguardManager.class).isKeyguardLocked()) {
executeShellCommand("input keyevent KEYCODE_WAKEUP");
@@ -73,6 +73,14 @@ public class WindowManagerPerfTestBase {
.addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
+ @After
+ public void tearDown() {
+ // Make sure that profiling is stopped if test fails.
+ if (sIsProfilingMethod) {
+ stopProfiling();
+ }
+ }
+
/**
* Executes shell command with reading the output. It may also used to block until the current
* command is completed.
@@ -93,12 +101,26 @@ public class WindowManagerPerfTestBase {
}
/** Starts method tracing on system server. */
- void startProfiling(String subPath) {
- executeShellCommand("am profile start system " + new File(BASE_OUT_PATH, subPath));
+ static void startProfiling(String subPath) {
+ if (!BASE_OUT_PATH.exists()) {
+ executeShellCommand("mkdir -p " + BASE_OUT_PATH);
+ }
+ final String samplingArg = WmPerfRunListener.sSamplingIntervalUs > 0
+ ? ("--sampling " + WmPerfRunListener.sSamplingIntervalUs)
+ : "";
+ executeShellCommand("am profile start " + samplingArg + " system "
+ + new File(BASE_OUT_PATH, subPath));
+ sIsProfilingMethod = true;
}
- void stopProfiling() {
+ static void stopProfiling() {
executeShellCommand("am profile stop system");
+ sIsProfilingMethod = false;
+ }
+
+ /** Returns how many iterations should run with method tracing. */
+ static int getProfilingIterations() {
+ return WmPerfRunListener.sProfilingIterations;
}
static void runWithShellPermissionIdentity(Runnable runnable) {
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java b/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java
index 6eb85aacb4e8..d955289e5f49 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java
@@ -31,6 +31,7 @@ import android.os.BatteryManager;
import android.os.Bundle;
import android.os.SystemClock;
import android.provider.Settings;
+import android.util.Log;
import android.view.WindowManagerPolicyConstants;
import android.wm.WindowManagerPerfTestBase.SettingsSession;
@@ -46,10 +47,22 @@ import java.util.List;
/** Prepare the preconditions before running performance test. */
public class WmPerfRunListener extends RunListener {
-
- private static final String OPTION_KILL_BACKGROUND = "kill-bg";
+ private static final String TAG = WmPerfRunListener.class.getSimpleName();
+
+ private static final String ARGUMENT_LOG_ONLY = "log";
+ private static final String ARGUMENT_KILL_BACKGROUND = "kill-bg";
+ private static final String ARGUMENT_PROFILING_ITERATIONS = "profiling-iterations";
+ private static final String ARGUMENT_PROFILING_SAMPLING = "profiling-sampling";
+ private static final String DEFAULT_PROFILING_ITERATIONS = "0";
+ private static final String DEFAULT_PROFILING_SAMPLING_US = "10";
private static final long KILL_BACKGROUND_WAIT_MS = 3000;
+ /** The requested iterations to run with method profiling. */
+ static int sProfilingIterations;
+
+ /** The interval of sample profiling in microseconds. */
+ static int sSamplingIntervalUs;
+
private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
private long mWaitPreconditionDoneMs = 500;
@@ -83,6 +96,16 @@ public class WmPerfRunListener extends RunListener {
@Override
public void testRunStarted(Description description) {
final Bundle arguments = InstrumentationRegistry.getArguments();
+ // If true, it only logs the method names without running.
+ final boolean skip = Boolean.parseBoolean(arguments.getString(ARGUMENT_LOG_ONLY, "false"));
+ Log.i(TAG, "arguments=" + arguments);
+ if (skip) {
+ return;
+ }
+ sProfilingIterations = Integer.parseInt(
+ arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS));
+ sSamplingIntervalUs = Integer.parseInt(
+ arguments.getString(ARGUMENT_PROFILING_SAMPLING, DEFAULT_PROFILING_SAMPLING_US));
// Use gesture navigation for consistency.
mNavigationModeSetting.set(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL);
@@ -97,7 +120,7 @@ public class WmPerfRunListener extends RunListener {
});
PhoneWindow.sendCloseSystemWindows(mContext, "WmPerfTests");
- if (Boolean.parseBoolean(arguments.getString(OPTION_KILL_BACKGROUND))) {
+ if (Boolean.parseBoolean(arguments.getString(ARGUMENT_KILL_BACKGROUND))) {
runWithShellPermissionIdentity(this::killBackgroundProcesses);
mWaitPreconditionDoneMs = KILL_BACKGROUND_WAIT_MS;
}
diff --git a/apex/jobscheduler/service/java/com/android/server/JobSchedulerBackgroundThread.java b/apex/jobscheduler/service/java/com/android/server/JobSchedulerBackgroundThread.java
index 91d254d16b09..a413f7b1f3ca 100644
--- a/apex/jobscheduler/service/java/com/android/server/JobSchedulerBackgroundThread.java
+++ b/apex/jobscheduler/service/java/com/android/server/JobSchedulerBackgroundThread.java
@@ -17,10 +17,13 @@
package com.android.server;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Trace;
+import java.util.concurrent.Executor;
+
/**
* Shared singleton background thread.
*
@@ -31,6 +34,7 @@ public final class JobSchedulerBackgroundThread extends HandlerThread {
private static final long SLOW_DELIVERY_THRESHOLD_MS = 30_000;
private static JobSchedulerBackgroundThread sInstance;
private static Handler sHandler;
+ private static Executor sHandlerExecutor;
private JobSchedulerBackgroundThread() {
super("jobscheduler.bg", android.os.Process.THREAD_PRIORITY_BACKGROUND);
@@ -45,6 +49,7 @@ public final class JobSchedulerBackgroundThread extends HandlerThread {
looper.setSlowLogThresholdMs(
SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
sHandler = new Handler(sInstance.getLooper());
+ sHandlerExecutor = new HandlerExecutor(sHandler);
}
}
@@ -63,4 +68,12 @@ public final class JobSchedulerBackgroundThread extends HandlerThread {
return sHandler;
}
}
+
+ /** Returns the singleton handler executor for JobSchedulerBackgroundThread */
+ public static Executor getExecutor() {
+ synchronized (JobSchedulerBackgroundThread.class) {
+ ensureThreadLocked();
+ return sHandlerExecutor;
+ }
+ }
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index a1a5004447a6..b35a7be1f689 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -166,7 +166,7 @@ class JobConcurrencyManager {
// Note: we can't directly do postDelayed(this::rampUpForScreenOn), because
// we need the exact same instance for removeCallbacks().
mHandler.postDelayed(mRampUpForScreenOff,
- mConstants.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.getValue());
+ mConstants.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS);
}
}
}
@@ -189,7 +189,7 @@ class JobConcurrencyManager {
}
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
if ((mLastScreenOffRealtime
- + mConstants.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.getValue())
+ + mConstants.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS)
> now) {
return;
}
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 3234b274eaa7..cf4caea9c487 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -39,7 +39,6 @@ import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -50,7 +49,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ServiceInfo;
-import android.database.ContentObserver;
import android.net.Uri;
import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
@@ -67,11 +65,10 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.os.WorkSource;
-import android.provider.Settings;
+import android.provider.DeviceConfig;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
-import android.util.KeyValueListParser;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -88,6 +85,7 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.server.AppStateTracker;
import com.android.server.AppStateTrackerImpl;
import com.android.server.DeviceIdleInternal;
+import com.android.server.JobSchedulerBackgroundThread;
import com.android.server.LocalServices;
import com.android.server.SystemService.TargetUser;
import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
@@ -329,39 +327,70 @@ public class JobSchedulerService extends com.android.server.SystemService
// -- Pre-allocated temporaries only for use in assignJobsToContextsLocked --
- private class ConstantsObserver extends ContentObserver {
- private ContentResolver mResolver;
-
- public ConstantsObserver(Handler handler) {
- super(handler);
- }
-
- public void start(ContentResolver resolver) {
- mResolver = resolver;
- mResolver.registerContentObserver(Settings.Global.getUriFor(
- Settings.Global.JOB_SCHEDULER_CONSTANTS), false, this);
- updateConstants();
+ private class ConstantsObserver implements DeviceConfig.OnPropertiesChangedListener {
+ public void start() {
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ JobSchedulerBackgroundThread.getExecutor(), this);
+ // Load all the constants.
+ onPropertiesChanged(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER));
}
@Override
- public void onChange(boolean selfChange, Uri uri) {
- updateConstants();
- }
-
- private void updateConstants() {
+ public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ boolean apiQuotaScheduleUpdated = false;
+ boolean concurrencyUpdated = false;
synchronized (mLock) {
- try {
- mConstants.updateConstantsLocked(Settings.Global.getString(mResolver,
- Settings.Global.JOB_SCHEDULER_CONSTANTS));
- for (int controller = 0; controller < mControllers.size(); controller++) {
- final StateController sc = mControllers.get(controller);
- sc.onConstantsUpdatedLocked();
+ for (String name : properties.getKeyset()) {
+ if (name == null) {
+ continue;
}
- updateQuotaTracker();
- } catch (IllegalArgumentException e) {
- // Failed to parse the settings string, log this and move on
- // with defaults.
- Slog.e(TAG, "Bad jobscheduler settings", e);
+ switch (name) {
+ case Constants.KEY_ENABLE_API_QUOTAS:
+ case Constants.KEY_API_QUOTA_SCHEDULE_COUNT:
+ case Constants.KEY_API_QUOTA_SCHEDULE_WINDOW_MS:
+ case Constants.KEY_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT:
+ case Constants.KEY_API_QUOTA_SCHEDULE_THROW_EXCEPTION:
+ if (!apiQuotaScheduleUpdated) {
+ mConstants.updateApiQuotaConstantsLocked();
+ updateQuotaTracker();
+ apiQuotaScheduleUpdated = true;
+ }
+ break;
+ case Constants.KEY_MIN_READY_NON_ACTIVE_JOBS_COUNT:
+ case Constants.KEY_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS:
+ mConstants.updateBatchingConstantsLocked();
+ break;
+ case Constants.KEY_HEAVY_USE_FACTOR:
+ case Constants.KEY_MODERATE_USE_FACTOR:
+ mConstants.updateUseFactorConstantsLocked();
+ break;
+ case Constants.KEY_SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS:
+ if (!concurrencyUpdated) {
+ mConstants.updateConcurrencyConstantsLocked();
+ concurrencyUpdated = true;
+ }
+ break;
+ case Constants.KEY_MIN_LINEAR_BACKOFF_TIME_MS:
+ case Constants.KEY_MIN_EXP_BACKOFF_TIME_MS:
+ mConstants.updateBackoffConstantsLocked();
+ break;
+ case Constants.KEY_CONN_CONGESTION_DELAY_FRAC:
+ case Constants.KEY_CONN_PREFETCH_RELAX_FRAC:
+ mConstants.updateConnectivityConstantsLocked();
+ break;
+ default:
+ // Too many max_job_* strings to list.
+ if (name.startsWith(Constants.KEY_PREFIX_MAX_JOB)
+ && !concurrencyUpdated) {
+ mConstants.updateConcurrencyConstantsLocked();
+ concurrencyUpdated = true;
+ }
+ break;
+ }
+ }
+ for (int controller = 0; controller < mControllers.size(); controller++) {
+ final StateController sc = mControllers.get(controller);
+ sc.onConstantsUpdatedLocked();
}
}
}
@@ -376,53 +405,52 @@ public class JobSchedulerService extends com.android.server.SystemService
}
static class MaxJobCounts {
- private final KeyValueListParser.IntValue mTotal;
- private final KeyValueListParser.IntValue mMaxBg;
- private final KeyValueListParser.IntValue mMinBg;
+ private final int mTotalDefault;
+ private final String mTotalKey;
+ private final int mMaxBgDefault;
+ private final String mMaxBgKey;
+ private final int mMinBgDefault;
+ private final String mMinBgKey;
+ private int mTotal;
+ private int mMaxBg;
+ private int mMinBg;
MaxJobCounts(int totalDefault, String totalKey,
int maxBgDefault, String maxBgKey, int minBgDefault, String minBgKey) {
- mTotal = new KeyValueListParser.IntValue(totalKey, totalDefault);
- mMaxBg = new KeyValueListParser.IntValue(maxBgKey, maxBgDefault);
- mMinBg = new KeyValueListParser.IntValue(minBgKey, minBgDefault);
+ mTotalKey = totalKey;
+ mTotal = mTotalDefault = totalDefault;
+ mMaxBgKey = maxBgKey;
+ mMaxBg = mMaxBgDefault = maxBgDefault;
+ mMinBgKey = minBgKey;
+ mMinBg = mMinBgDefault = minBgDefault;
}
- public void parse(KeyValueListParser parser) {
- mTotal.parse(parser);
- mMaxBg.parse(parser);
- mMinBg.parse(parser);
+ public void update() {
+ mTotal = DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ mTotalKey, mTotalDefault);
+ mMaxBg = DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ mMaxBgKey, mMaxBgDefault);
+ mMinBg = DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ mMinBgKey, mMinBgDefault);
- if (mTotal.getValue() < 1) {
- mTotal.setValue(1);
- } else if (mTotal.getValue() > MAX_JOB_CONTEXTS_COUNT) {
- mTotal.setValue(MAX_JOB_CONTEXTS_COUNT);
- }
+ // Ensure total in the range [1, MAX_JOB_CONTEXTS_COUNT].
+ mTotal = Math.min(Math.max(1, mTotal), MAX_JOB_CONTEXTS_COUNT);
- if (mMaxBg.getValue() < 1) {
- mMaxBg.setValue(1);
- } else if (mMaxBg.getValue() > mTotal.getValue()) {
- mMaxBg.setValue(mTotal.getValue());
- }
- if (mMinBg.getValue() < 0) {
- mMinBg.setValue(0);
- } else {
- if (mMinBg.getValue() > mMaxBg.getValue()) {
- mMinBg.setValue(mMaxBg.getValue());
- }
- if (mMinBg.getValue() >= mTotal.getValue()) {
- mMinBg.setValue(mTotal.getValue() - 1);
- }
- }
+ // Ensure maxBg in the range [1, total].
+ mMaxBg = Math.min(Math.max(1, mMaxBg), mTotal);
+
+ // Ensure minBg in the range [0, min(maxBg, total - 1)]
+ mMinBg = Math.min(Math.max(0, mMinBg), Math.min(mMaxBg, mTotal - 1));
}
/** Total number of jobs to run simultaneously. */
public int getMaxTotal() {
- return mTotal.getValue();
+ return mTotal;
}
/** Max number of BG (== owned by non-TOP apps) jobs to run simultaneously. */
public int getMaxBg() {
- return mMaxBg.getValue();
+ return mMaxBg;
}
/**
@@ -430,20 +458,34 @@ public class JobSchedulerService extends com.android.server.SystemService
* pending, rather than always running the TOTAL number of FG jobs.
*/
public int getMinBg() {
- return mMinBg.getValue();
+ return mMinBg;
}
public void dump(PrintWriter pw, String prefix) {
- mTotal.dump(pw, prefix);
- mMaxBg.dump(pw, prefix);
- mMinBg.dump(pw, prefix);
+ pw.print(prefix);
+ pw.print(mTotalKey);
+ pw.print("=");
+ pw.print(mTotal);
+ pw.println();
+
+ pw.print(prefix);
+ pw.print(mMaxBgKey);
+ pw.print("=");
+ pw.print(mMaxBg);
+ pw.println();
+
+ pw.print(prefix);
+ pw.print(mMinBgKey);
+ pw.print("=");
+ pw.print(mMinBg);
+ pw.println();
}
public void dumpProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
- mTotal.dumpProto(proto, MaxJobCountsProto.TOTAL_JOBS);
- mMaxBg.dumpProto(proto, MaxJobCountsProto.MAX_BG);
- mMinBg.dumpProto(proto, MaxJobCountsProto.MIN_BG);
+ proto.write(MaxJobCountsProto.TOTAL_JOBS, mTotal);
+ proto.write(MaxJobCountsProto.MAX_BG, mMaxBg);
+ proto.write(MaxJobCountsProto.MIN_BG, mMinBg);
proto.end(token);
}
}
@@ -476,23 +518,11 @@ public class JobSchedulerService extends com.android.server.SystemService
}
/**
- * All times are in milliseconds. These constants are kept synchronized with the system
- * global Settings. Any access to this class or its fields should be done while
+ * All times are in milliseconds. Any access to this class or its fields should be done while
* holding the JobSchedulerService.mLock lock.
*/
public static class Constants {
// Key names stored in the settings value.
- // TODO(124466289): remove deprecated flags when we migrate to DeviceConfig
- private static final String DEPRECATED_KEY_MIN_IDLE_COUNT = "min_idle_count";
- private static final String DEPRECATED_KEY_MIN_CHARGING_COUNT = "min_charging_count";
- private static final String DEPRECATED_KEY_MIN_BATTERY_NOT_LOW_COUNT =
- "min_battery_not_low_count";
- private static final String DEPRECATED_KEY_MIN_STORAGE_NOT_LOW_COUNT =
- "min_storage_not_low_count";
- private static final String DEPRECATED_KEY_MIN_CONNECTIVITY_COUNT =
- "min_connectivity_count";
- private static final String DEPRECATED_KEY_MIN_CONTENT_COUNT = "min_content_count";
- private static final String DEPRECATED_KEY_MIN_READY_JOBS_COUNT = "min_ready_jobs_count";
private static final String KEY_MIN_READY_NON_ACTIVE_JOBS_COUNT =
"min_ready_non_active_jobs_count";
private static final String KEY_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS =
@@ -500,28 +530,10 @@ public class JobSchedulerService extends com.android.server.SystemService
private static final String KEY_HEAVY_USE_FACTOR = "heavy_use_factor";
private static final String KEY_MODERATE_USE_FACTOR = "moderate_use_factor";
- // The following values used to be used on P and below. Do not reuse them.
- private static final String DEPRECATED_KEY_FG_JOB_COUNT = "fg_job_count";
- private static final String DEPRECATED_KEY_BG_NORMAL_JOB_COUNT = "bg_normal_job_count";
- private static final String DEPRECATED_KEY_BG_MODERATE_JOB_COUNT = "bg_moderate_job_count";
- private static final String DEPRECATED_KEY_BG_LOW_JOB_COUNT = "bg_low_job_count";
- private static final String DEPRECATED_KEY_BG_CRITICAL_JOB_COUNT = "bg_critical_job_count";
-
- private static final String DEPRECATED_KEY_MAX_STANDARD_RESCHEDULE_COUNT
- = "max_standard_reschedule_count";
- private static final String DEPRECATED_KEY_MAX_WORK_RESCHEDULE_COUNT =
- "max_work_reschedule_count";
- private static final String KEY_MIN_LINEAR_BACKOFF_TIME = "min_linear_backoff_time";
- private static final String KEY_MIN_EXP_BACKOFF_TIME = "min_exp_backoff_time";
- private static final String DEPRECATED_KEY_STANDBY_HEARTBEAT_TIME =
- "standby_heartbeat_time";
- private static final String DEPRECATED_KEY_STANDBY_WORKING_BEATS = "standby_working_beats";
- private static final String DEPRECATED_KEY_STANDBY_FREQUENT_BEATS =
- "standby_frequent_beats";
- private static final String DEPRECATED_KEY_STANDBY_RARE_BEATS = "standby_rare_beats";
+ private static final String KEY_MIN_LINEAR_BACKOFF_TIME_MS = "min_linear_backoff_time_ms";
+ private static final String KEY_MIN_EXP_BACKOFF_TIME_MS = "min_exp_backoff_time_ms";
private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac";
private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac";
- private static final String DEPRECATED_KEY_USE_HEARTBEATS = "use_heartbeats";
private static final String KEY_ENABLE_API_QUOTAS = "enable_api_quotas";
private static final String KEY_API_QUOTA_SCHEDULE_COUNT = "aq_schedule_count";
private static final String KEY_API_QUOTA_SCHEDULE_WINDOW_MS = "aq_schedule_window_ms";
@@ -530,12 +542,15 @@ public class JobSchedulerService extends com.android.server.SystemService
private static final String KEY_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT =
"aq_schedule_return_failure";
+ private static final String KEY_SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS =
+ "screen_off_job_concurrency_increase_delay_ms";
+
private static final int DEFAULT_MIN_READY_NON_ACTIVE_JOBS_COUNT = 5;
private static final long DEFAULT_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = 31 * MINUTE_IN_MILLIS;
private static final float DEFAULT_HEAVY_USE_FACTOR = .9f;
private static final float DEFAULT_MODERATE_USE_FACTOR = .5f;
- private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
- private static final long DEFAULT_MIN_EXP_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
+ private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME_MS = JobInfo.MIN_BACKOFF_MILLIS;
+ private static final long DEFAULT_MIN_EXP_BACKOFF_TIME_MS = JobInfo.MIN_BACKOFF_MILLIS;
private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
private static final boolean DEFAULT_ENABLE_API_QUOTAS = true;
@@ -543,6 +558,7 @@ public class JobSchedulerService extends com.android.server.SystemService
private static final long DEFAULT_API_QUOTA_SCHEDULE_WINDOW_MS = MINUTE_IN_MILLIS;
private static final boolean DEFAULT_API_QUOTA_SCHEDULE_THROW_EXCEPTION = true;
private static final boolean DEFAULT_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = false;
+ private static final long DEFAULT_SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS = 30_000;
/**
* Minimum # of non-ACTIVE jobs for which the JMS will be happy running some work early.
@@ -564,59 +580,61 @@ public class JobSchedulerService extends com.android.server.SystemService
*/
float MODERATE_USE_FACTOR = DEFAULT_MODERATE_USE_FACTOR;
+ /** Prefix for all of the max_job constants. */
+ private static final String KEY_PREFIX_MAX_JOB = "max_job_";
+
// Max job counts for screen on / off, for each memory trim level.
final MaxJobCountsPerMemoryTrimLevel MAX_JOB_COUNTS_SCREEN_ON =
new MaxJobCountsPerMemoryTrimLevel(
new MaxJobCounts(
- 8, "max_job_total_on_normal",
- 6, "max_job_max_bg_on_normal",
- 2, "max_job_min_bg_on_normal"),
+ 8, KEY_PREFIX_MAX_JOB + "total_on_normal",
+ 6, KEY_PREFIX_MAX_JOB + "max_bg_on_normal",
+ 2, KEY_PREFIX_MAX_JOB + "min_bg_on_normal"),
new MaxJobCounts(
- 8, "max_job_total_on_moderate",
- 4, "max_job_max_bg_on_moderate",
- 2, "max_job_min_bg_on_moderate"),
+ 8, KEY_PREFIX_MAX_JOB + "total_on_moderate",
+ 4, KEY_PREFIX_MAX_JOB + "max_bg_on_moderate",
+ 2, KEY_PREFIX_MAX_JOB + "min_bg_on_moderate"),
new MaxJobCounts(
- 5, "max_job_total_on_low",
- 1, "max_job_max_bg_on_low",
- 1, "max_job_min_bg_on_low"),
+ 5, KEY_PREFIX_MAX_JOB + "total_on_low",
+ 1, KEY_PREFIX_MAX_JOB + "max_bg_on_low",
+ 1, KEY_PREFIX_MAX_JOB + "min_bg_on_low"),
new MaxJobCounts(
- 5, "max_job_total_on_critical",
- 1, "max_job_max_bg_on_critical",
- 1, "max_job_min_bg_on_critical"));
+ 5, KEY_PREFIX_MAX_JOB + "total_on_critical",
+ 1, KEY_PREFIX_MAX_JOB + "max_bg_on_critical",
+ 1, KEY_PREFIX_MAX_JOB + "min_bg_on_critical"));
final MaxJobCountsPerMemoryTrimLevel MAX_JOB_COUNTS_SCREEN_OFF =
new MaxJobCountsPerMemoryTrimLevel(
new MaxJobCounts(
- 10, "max_job_total_off_normal",
- 6, "max_job_max_bg_off_normal",
- 2, "max_job_min_bg_off_normal"),
+ 10, KEY_PREFIX_MAX_JOB + "total_off_normal",
+ 6, KEY_PREFIX_MAX_JOB + "max_bg_off_normal",
+ 2, KEY_PREFIX_MAX_JOB + "min_bg_off_normal"),
new MaxJobCounts(
- 10, "max_job_total_off_moderate",
- 4, "max_job_max_bg_off_moderate",
- 2, "max_job_min_bg_off_moderate"),
+ 10, KEY_PREFIX_MAX_JOB + "total_off_moderate",
+ 4, KEY_PREFIX_MAX_JOB + "max_bg_off_moderate",
+ 2, KEY_PREFIX_MAX_JOB + "min_bg_off_moderate"),
new MaxJobCounts(
- 5, "max_job_total_off_low",
- 1, "max_job_max_bg_off_low",
- 1, "max_job_min_bg_off_low"),
+ 5, KEY_PREFIX_MAX_JOB + "total_off_low",
+ 1, KEY_PREFIX_MAX_JOB + "max_bg_off_low",
+ 1, KEY_PREFIX_MAX_JOB + "min_bg_off_low"),
new MaxJobCounts(
- 5, "max_job_total_off_critical",
- 1, "max_job_max_bg_off_critical",
- 1, "max_job_min_bg_off_critical"));
+ 5, KEY_PREFIX_MAX_JOB + "total_off_critical",
+ 1, KEY_PREFIX_MAX_JOB + "max_bg_off_critical",
+ 1, KEY_PREFIX_MAX_JOB + "min_bg_off_critical"));
/** Wait for this long after screen off before increasing the job concurrency. */
- final KeyValueListParser.IntValue SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS =
- new KeyValueListParser.IntValue(
- "screen_off_job_concurrency_increase_delay_ms", 30_000);
+ long SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS =
+ DEFAULT_SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS;
/**
* The minimum backoff time to allow for linear backoff.
*/
- long MIN_LINEAR_BACKOFF_TIME = DEFAULT_MIN_LINEAR_BACKOFF_TIME;
+ long MIN_LINEAR_BACKOFF_TIME_MS = DEFAULT_MIN_LINEAR_BACKOFF_TIME_MS;
/**
* The minimum backoff time to allow for exponential backoff.
*/
- long MIN_EXP_BACKOFF_TIME = DEFAULT_MIN_EXP_BACKOFF_TIME;
+ long MIN_EXP_BACKOFF_TIME_MS = DEFAULT_MIN_EXP_BACKOFF_TIME_MS;
/**
* The fraction of a job's running window that must pass before we
@@ -652,61 +670,78 @@ public class JobSchedulerService extends com.android.server.SystemService
public boolean API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT =
DEFAULT_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT;
- private final KeyValueListParser mParser = new KeyValueListParser(',');
-
- void updateConstantsLocked(String value) {
- try {
- mParser.setString(value);
- } catch (Exception e) {
- // Failed to parse the settings string, log this and move on
- // with defaults.
- Slog.e(TAG, "Bad jobscheduler settings", e);
- }
-
- MIN_READY_NON_ACTIVE_JOBS_COUNT = mParser.getInt(
+ private void updateBatchingConstantsLocked() {
+ MIN_READY_NON_ACTIVE_JOBS_COUNT = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_MIN_READY_NON_ACTIVE_JOBS_COUNT,
DEFAULT_MIN_READY_NON_ACTIVE_JOBS_COUNT);
- MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = mParser.getLong(
+ MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS,
DEFAULT_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS);
- HEAVY_USE_FACTOR = mParser.getFloat(KEY_HEAVY_USE_FACTOR,
+ }
+
+ private void updateUseFactorConstantsLocked() {
+ HEAVY_USE_FACTOR = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_HEAVY_USE_FACTOR,
DEFAULT_HEAVY_USE_FACTOR);
- MODERATE_USE_FACTOR = mParser.getFloat(KEY_MODERATE_USE_FACTOR,
+ MODERATE_USE_FACTOR = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_MODERATE_USE_FACTOR,
DEFAULT_MODERATE_USE_FACTOR);
+ }
- MAX_JOB_COUNTS_SCREEN_ON.normal.parse(mParser);
- MAX_JOB_COUNTS_SCREEN_ON.moderate.parse(mParser);
- MAX_JOB_COUNTS_SCREEN_ON.low.parse(mParser);
- MAX_JOB_COUNTS_SCREEN_ON.critical.parse(mParser);
+ void updateConcurrencyConstantsLocked() {
+ MAX_JOB_COUNTS_SCREEN_ON.normal.update();
+ MAX_JOB_COUNTS_SCREEN_ON.moderate.update();
+ MAX_JOB_COUNTS_SCREEN_ON.low.update();
+ MAX_JOB_COUNTS_SCREEN_ON.critical.update();
- MAX_JOB_COUNTS_SCREEN_OFF.normal.parse(mParser);
- MAX_JOB_COUNTS_SCREEN_OFF.moderate.parse(mParser);
- MAX_JOB_COUNTS_SCREEN_OFF.low.parse(mParser);
- MAX_JOB_COUNTS_SCREEN_OFF.critical.parse(mParser);
+ MAX_JOB_COUNTS_SCREEN_OFF.normal.update();
+ MAX_JOB_COUNTS_SCREEN_OFF.moderate.update();
+ MAX_JOB_COUNTS_SCREEN_OFF.low.update();
+ MAX_JOB_COUNTS_SCREEN_OFF.critical.update();
- SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.parse(mParser);
+ SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS,
+ DEFAULT_SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS);
+ }
- MIN_LINEAR_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_LINEAR_BACKOFF_TIME,
- DEFAULT_MIN_LINEAR_BACKOFF_TIME);
- MIN_EXP_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_EXP_BACKOFF_TIME,
- DEFAULT_MIN_EXP_BACKOFF_TIME);
- CONN_CONGESTION_DELAY_FRAC = mParser.getFloat(KEY_CONN_CONGESTION_DELAY_FRAC,
+ private void updateBackoffConstantsLocked() {
+ MIN_LINEAR_BACKOFF_TIME_MS = DeviceConfig.getLong(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_MIN_LINEAR_BACKOFF_TIME_MS,
+ DEFAULT_MIN_LINEAR_BACKOFF_TIME_MS);
+ MIN_EXP_BACKOFF_TIME_MS = DeviceConfig.getLong(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_MIN_EXP_BACKOFF_TIME_MS,
+ DEFAULT_MIN_EXP_BACKOFF_TIME_MS);
+ }
+
+ private void updateConnectivityConstantsLocked() {
+ CONN_CONGESTION_DELAY_FRAC = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_CONN_CONGESTION_DELAY_FRAC,
DEFAULT_CONN_CONGESTION_DELAY_FRAC);
- CONN_PREFETCH_RELAX_FRAC = mParser.getFloat(KEY_CONN_PREFETCH_RELAX_FRAC,
+ CONN_PREFETCH_RELAX_FRAC = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_CONN_PREFETCH_RELAX_FRAC,
DEFAULT_CONN_PREFETCH_RELAX_FRAC);
+ }
- ENABLE_API_QUOTAS = mParser.getBoolean(KEY_ENABLE_API_QUOTAS,
- DEFAULT_ENABLE_API_QUOTAS);
+ private void updateApiQuotaConstantsLocked() {
+ ENABLE_API_QUOTAS = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_ENABLE_API_QUOTAS, DEFAULT_ENABLE_API_QUOTAS);
// Set a minimum value on the quota limit so it's not so low that it interferes with
// legitimate use cases.
API_QUOTA_SCHEDULE_COUNT = Math.max(250,
- mParser.getInt(KEY_API_QUOTA_SCHEDULE_COUNT, DEFAULT_API_QUOTA_SCHEDULE_COUNT));
- API_QUOTA_SCHEDULE_WINDOW_MS = mParser.getDurationMillis(
+ DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_API_QUOTA_SCHEDULE_COUNT, DEFAULT_API_QUOTA_SCHEDULE_COUNT));
+ API_QUOTA_SCHEDULE_WINDOW_MS = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_API_QUOTA_SCHEDULE_WINDOW_MS, DEFAULT_API_QUOTA_SCHEDULE_WINDOW_MS);
- API_QUOTA_SCHEDULE_THROW_EXCEPTION = mParser.getBoolean(
+ API_QUOTA_SCHEDULE_THROW_EXCEPTION = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_API_QUOTA_SCHEDULE_THROW_EXCEPTION,
DEFAULT_API_QUOTA_SCHEDULE_THROW_EXCEPTION);
- API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = mParser.getBoolean(
+ API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT,
DEFAULT_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT);
}
@@ -731,10 +766,11 @@ public class JobSchedulerService extends com.android.server.SystemService
MAX_JOB_COUNTS_SCREEN_OFF.low.dump(pw, "");
MAX_JOB_COUNTS_SCREEN_OFF.critical.dump(pw, "");
- SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.dump(pw, "");
+ pw.print(KEY_SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS,
+ SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS).println();
- pw.print(KEY_MIN_LINEAR_BACKOFF_TIME, MIN_LINEAR_BACKOFF_TIME).println();
- pw.print(KEY_MIN_EXP_BACKOFF_TIME, MIN_EXP_BACKOFF_TIME).println();
+ pw.print(KEY_MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME_MS).println();
+ pw.print(KEY_MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME_MS).println();
pw.print(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
pw.print(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println();
@@ -760,11 +796,11 @@ public class JobSchedulerService extends com.android.server.SystemService
MAX_JOB_COUNTS_SCREEN_ON.dumpProto(proto, ConstantsProto.MAX_JOB_COUNTS_SCREEN_ON);
MAX_JOB_COUNTS_SCREEN_OFF.dumpProto(proto, ConstantsProto.MAX_JOB_COUNTS_SCREEN_OFF);
- SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.dumpProto(proto,
- ConstantsProto.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS);
+ proto.write(ConstantsProto.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS,
+ SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS);
- proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME);
- proto.write(ConstantsProto.MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME);
+ proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME_MS);
+ proto.write(ConstantsProto.MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME_MS);
proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC);
proto.write(ConstantsProto.CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC);
@@ -1407,7 +1443,7 @@ public class JobSchedulerService extends com.android.server.SystemService
mHandler = new JobHandler(context.getMainLooper());
mConstants = new Constants();
- mConstantsObserver = new ConstantsObserver(mHandler);
+ mConstantsObserver = new ConstantsObserver();
mJobSchedulerStub = new JobSchedulerStub();
mConcurrencyManager = new JobConcurrencyManager(this);
@@ -1521,7 +1557,7 @@ public class JobSchedulerService extends com.android.server.SystemService
@Override
public void onBootPhase(int phase) {
if (PHASE_SYSTEM_SERVICES_READY == phase) {
- mConstantsObserver.start(getContext().getContentResolver());
+ mConstantsObserver.start();
for (StateController controller : mControllers) {
controller.onSystemServicesReady();
}
@@ -1693,8 +1729,8 @@ public class JobSchedulerService extends com.android.server.SystemService
switch (job.getBackoffPolicy()) {
case JobInfo.BACKOFF_POLICY_LINEAR: {
long backoff = initialBackoffMillis;
- if (backoff < mConstants.MIN_LINEAR_BACKOFF_TIME) {
- backoff = mConstants.MIN_LINEAR_BACKOFF_TIME;
+ if (backoff < mConstants.MIN_LINEAR_BACKOFF_TIME_MS) {
+ backoff = mConstants.MIN_LINEAR_BACKOFF_TIME_MS;
}
delayMillis = backoff * backoffAttempts;
} break;
@@ -1704,8 +1740,8 @@ public class JobSchedulerService extends com.android.server.SystemService
}
case JobInfo.BACKOFF_POLICY_EXPONENTIAL: {
long backoff = initialBackoffMillis;
- if (backoff < mConstants.MIN_EXP_BACKOFF_TIME) {
- backoff = mConstants.MIN_EXP_BACKOFF_TIME;
+ if (backoff < mConstants.MIN_EXP_BACKOFF_TIME_MS) {
+ backoff = mConstants.MIN_EXP_BACKOFF_TIME_MS;
}
delayMillis = (long) Math.scalb(backoff, backoffAttempts - 1);
} break;
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 6bc95bf8bc75..c033138d5f20 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -2131,7 +2131,7 @@ public class AppStandbyController implements AppStandbyInternal {
}
public List<UserHandle> getValidCrossProfileTargets(String pkg, int userId) {
- final int uid = mPackageManagerInternal.getPackageUidInternal(pkg, 0, userId);
+ final int uid = mPackageManagerInternal.getPackageUid(pkg, /* flags= */ 0, userId);
final AndroidPackage aPkg = mPackageManagerInternal.getPackage(uid);
if (uid < 0
|| aPkg == null
diff --git a/api/current.txt b/api/current.txt
index 9e0d88ecdfd1..c6af6beca60b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11901,8 +11901,8 @@ package android.content.pm {
field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR;
field public static final int INVALID_ID = -1; // 0xffffffff
field public static final int STAGED_SESSION_ACTIVATION_FAILED = 2; // 0x2
+ field public static final int STAGED_SESSION_CONFLICT = 4; // 0x4
field public static final int STAGED_SESSION_NO_ERROR = 0; // 0x0
- field public static final int STAGED_SESSION_OTHER_ERROR = 4; // 0x4
field public static final int STAGED_SESSION_UNKNOWN = 3; // 0x3
field public static final int STAGED_SESSION_VERIFICATION_FAILED = 1; // 0x1
}
@@ -14250,6 +14250,10 @@ package android.graphics {
enum_constant public static final android.graphics.BlurMaskFilter.Blur SOLID;
}
+ public final class BlurShader extends android.graphics.Shader {
+ ctor public BlurShader(float, float, @Nullable android.graphics.Shader);
+ }
+
public class Camera {
ctor public Camera();
method public void applyToCanvas(android.graphics.Canvas);
@@ -31620,6 +31624,7 @@ package android.net.wifi {
method @Nullable public String getPassphrase();
method @Nullable public android.net.wifi.hotspot2.PasspointConfiguration getPasspointConfig();
method @IntRange(from=0) public int getPriority();
+ method public int getPriorityGroup();
method @Nullable public String getSsid();
method public boolean isAppInteractionRequired();
method public boolean isCredentialSharedWithUser();
@@ -31646,6 +31651,7 @@ package android.net.wifi {
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserInteractionRequired(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPasspointConfig(@NonNull android.net.wifi.hotspot2.PasspointConfiguration);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(@IntRange(from=0) int);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriorityGroup(int);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setSsid(@NonNull String);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setUntrusted(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiEnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
@@ -36733,9 +36739,11 @@ package android.os {
public final class PowerManager {
method public void addThermalStatusListener(@NonNull android.os.PowerManager.OnThermalStatusChangedListener);
method public void addThermalStatusListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.PowerManager.OnThermalStatusChangedListener);
+ method @Nullable public java.time.Duration getBatteryDischargePrediction();
method public int getCurrentThermalStatus();
method public int getLocationPowerSaveMode();
method public float getThermalHeadroom(@IntRange(from=0, to=60) int);
+ method public boolean isBatteryDischargePredictionPersonalized();
method public boolean isDeviceIdleMode();
method public boolean isIgnoringBatteryOptimizations(String);
method public boolean isInteractive();
@@ -47836,6 +47844,7 @@ package android.telephony {
method public void onDataConnectionStateChanged(int);
method public void onDataConnectionStateChanged(int, int);
method @RequiresPermission("android.permission.READ_PHONE_STATE") public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
+ method public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
method public void onMessageWaitingIndicatorChanged(boolean);
method @RequiresPermission("android.permission.MODIFY_PHONE_STATE") public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
@@ -48352,7 +48361,9 @@ package android.telephony {
method @Deprecated public String iccTransmitApduBasicChannel(int, int, int, int, int, String);
method @Deprecated public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
method public boolean isConcurrentVoiceAndDataSupported();
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isDataConnectionAllowed();
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean isDataEnabled();
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledForReason(int);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
method public boolean isEmergencyNumber(@NonNull String);
method public boolean isHearingAidCompatibilitySupported();
@@ -48374,6 +48385,7 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledForReason(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setForbiddenPlmns(@NonNull java.util.List<java.lang.String>);
method public boolean setLine1NumberForDisplay(String, String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setNetworkSelectionModeAutomatic();
@@ -48421,6 +48433,10 @@ package android.telephony {
field public static final int DATA_CONNECTING = 1; // 0x1
field public static final int DATA_DISCONNECTED = 0; // 0x0
field public static final int DATA_DISCONNECTING = 4; // 0x4
+ field public static final int DATA_ENABLED_REASON_CARRIER = 2; // 0x2
+ field public static final int DATA_ENABLED_REASON_POLICY = 1; // 0x1
+ field public static final int DATA_ENABLED_REASON_THERMAL = 3; // 0x3
+ field public static final int DATA_ENABLED_REASON_USER = 0; // 0x0
field public static final int DATA_SUSPENDED = 3; // 0x3
field public static final int DATA_UNKNOWN = -1; // 0xffffffff
field public static final String EXTRA_ACTIVE_SIM_SUPPORTED_COUNT = "android.telephony.extra.ACTIVE_SIM_SUPPORTED_COUNT";
@@ -55185,7 +55201,7 @@ package android.view {
}
public class ViewPropertyAnimator {
- method public android.view.ViewPropertyAnimator alpha(float);
+ method public android.view.ViewPropertyAnimator alpha(@FloatRange(from=0.0f, to=1.0f) float);
method public android.view.ViewPropertyAnimator alphaBy(float);
method public void cancel();
method public long getDuration();
diff --git a/api/system-current.txt b/api/system-current.txt
index 3ab164554da6..41e859363581 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -8394,6 +8394,7 @@ package android.os {
method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplaySuppressedForToken(@NonNull String);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSaveEnabled(boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSavePolicy(@NonNull android.os.BatterySaverPolicyConfig);
+ method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void setBatteryDischargePrediction(@NonNull java.time.Duration, boolean);
method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setDynamicPowerSaveHint(boolean, int);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveModeEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void suppressAmbientDisplay(@NonNull String, boolean);
@@ -10816,7 +10817,8 @@ package android.telephony {
public class PhoneStateListener {
method public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
- method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
+ method @Deprecated public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
+ method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber);
method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
method public void onRadioPowerStateChanged(int);
@@ -11233,10 +11235,8 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataConnectionAllowed();
method public boolean isDataConnectivityPossible();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledWithReason(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean isIccLockEnabled();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
@@ -11268,7 +11268,6 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledWithReason(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean);
@@ -11306,10 +11305,6 @@ package android.telephony {
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
- field public static final int DATA_ENABLED_REASON_CARRIER = 2; // 0x2
- field public static final int DATA_ENABLED_REASON_POLICY = 1; // 0x1
- field public static final int DATA_ENABLED_REASON_THERMAL = 3; // 0x3
- field public static final int DATA_ENABLED_REASON_USER = 0; // 0x0
field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION";
field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID";
field public static final String EXTRA_PHONE_IN_ECM_STATE = "android.telephony.extra.PHONE_IN_ECM_STATE";
@@ -12744,8 +12739,8 @@ package android.webkit {
public interface PacProcessor {
method @Nullable public String findProxyForUrl(@NonNull String);
method @NonNull public static android.webkit.PacProcessor getInstance();
- method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(long);
- method public default long getNetworkHandle();
+ method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(@Nullable android.net.Network);
+ method @Nullable public default android.net.Network getNetwork();
method public default void releasePacProcessor();
method public boolean setProxyScript(@NonNull String);
}
@@ -12886,7 +12881,7 @@ package android.webkit {
method public android.webkit.CookieManager getCookieManager();
method public android.webkit.GeolocationPermissions getGeolocationPermissions();
method @NonNull public default android.webkit.PacProcessor getPacProcessor();
- method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(long);
+ method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(@Nullable android.net.Network);
method public android.webkit.ServiceWorkerController getServiceWorkerController();
method public android.webkit.WebViewFactoryProvider.Statics getStatics();
method @Deprecated public android.webkit.TokenBindingService getTokenBindingService();
diff --git a/api/test-current.txt b/api/test-current.txt
index 342bd81ac69b..529dcf71ef6e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2799,8 +2799,10 @@ package android.os {
public final class PowerManager {
method @RequiresPermission("android.permission.POWER_SAVER") public int getPowerSaveModeTrigger();
+ method @RequiresPermission("android.permission.DEVICE_POWER") public void setBatteryDischargePrediction(@NonNull java.time.Duration, boolean);
method @RequiresPermission("android.permission.POWER_SAVER") public boolean setDynamicPowerSaveHint(boolean, int);
method @RequiresPermission(anyOf={"android.permission.DEVICE_POWER", "android.permission.POWER_SAVER"}) public boolean setPowerSaveModeEnabled(boolean);
+ field public static final String ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED = "android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED";
field public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1; // 0x1
field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0
}
@@ -3238,6 +3240,7 @@ package android.provider {
field public static final String NAMESPACE_AUTOFILL = "autofill";
field public static final String NAMESPACE_BIOMETRICS = "biometrics";
field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
+ field public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler";
field public static final String NAMESPACE_PERMISSIONS = "permissions";
field public static final String NAMESPACE_PRIVACY = "privacy";
field public static final String NAMESPACE_ROLLBACK = "rollback";
@@ -4073,7 +4076,8 @@ package android.telephony {
}
public class PhoneStateListener {
- method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
+ method @Deprecated public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
+ method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber);
field @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000
field @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000
@@ -5574,7 +5578,7 @@ package android.window {
method @BinderThread public void onTaskAppeared(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.view.SurfaceControl);
method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void registerOrganizer(int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void registerOrganizer();
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setInterceptBackPressedOnTaskRoot(boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static void setLaunchRoot(int, @NonNull android.window.WindowContainerToken);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void unregisterOrganizer();
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index dc1612575f38..13bf197aa9dc 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -554,6 +554,10 @@ status_t IncidentService::command(FILE* in, FILE* out, FILE* err, Vector<String8
return NO_ERROR;
}
if (!args[0].compare(String8("section"))) {
+ if (argCount == 1) {
+ fprintf(out, "Not enough arguments for section\n");
+ return NO_ERROR;
+ }
int id = atoi(args[1]);
int idx = 0;
while (SECTION_LIST[idx] != NULL) {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 6b335ee1b923..e6e22bac05d4 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -485,6 +485,9 @@ message Atom {
NetworkTetheringReported network_tethering_reported =
303 [(module) = "network_tethering"];
ImeTouchReported ime_touch_reported = 304 [(module) = "sysui"];
+ UIInteractionFrameInfoReported ui_interaction_frame_info_reported =
+ 305 [(module) = "framework"];
+ UIActionLatencyReported ui_action_latency_reported = 306 [(module) = "framework"];
// StatsdStats tracks platform atoms with ids upto 500.
// Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
@@ -4004,7 +4007,7 @@ message Notification {
optional bool is_group_summary = 5;
// The section of the shade that the notification is in.
- // See NotificationSectionsManager.PriorityBucket.
+ // See SystemUI Notifications.proto.
enum NotificationSection {
SECTION_UNKNOWN = 0;
SECTION_HEADS_UP = 1;
@@ -4012,6 +4015,7 @@ message Notification {
SECTION_PEOPLE = 3;
SECTION_ALERTING = 4;
SECTION_SILENT = 5;
+ SECTION_FOREGROUND_SERVICE = 6;
}
optional NotificationSection section = 6;
}
@@ -5054,6 +5058,54 @@ message BlobOpened{
optional Result result = 4;
}
+/**
+ * Event to track Jank for various system interactions.
+ *
+ * Logged from:
+ * frameworks/base/core/java/android/os/aot/FrameTracker.java
+ */
+message UIInteractionFrameInfoReported {
+ enum InteractionType {
+ UNKNOWN = 0;
+ NOTIFICATION_SHADE_SWIPE = 1;
+ }
+
+ optional InteractionType interaction_type = 1;
+
+ // Number of frames rendered during the interaction.
+ optional int64 total_frames = 2;
+
+ // Number of frames that were skipped in rendering during the interaction.
+ optional int64 missed_frames = 3;
+
+ // Maximum time it took to render a single frame during the interaction.
+ optional int64 max_frame_time_nanos = 4;
+}
+
+/**
+ * Event to track various latencies in SystemUI.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/util/LatencyTracker.java
+ */
+message UIActionLatencyReported {
+ enum ActionType {
+ UNKNOWN = 0;
+ ACTION_EXPAND_PANEL = 1;
+ ACTION_TOGGLE_RECENTS = 2;
+ ACTION_FINGERPRINT_WAKE_AND_UNLOCK = 3;
+ ACTION_CHECK_CREDENTIAL = 4;
+ ACTION_CHECK_CREDENTIAL_UNLOCKED = 5;
+ ACTION_TURN_ON_SCREEN = 6;
+ ACTION_ROTATE_SCREEN = 7;
+ ACTION_FACE_WAKE_AND_UNLOCK = 8;
+ }
+
+ optional ActionType action = 1;
+
+ optional int64 latency_millis = 2;
+}
+
//////////////////////////////////////////////////////////////////////
// Pulled atoms below this line //
//////////////////////////////////////////////////////////////////////
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index 7a1ece94fd3e..3b65f8225ee9 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -38,9 +38,23 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf
const vector<sp<ConditionTracker>>& allConditionTrackers,
const unordered_map<int64_t, int>& conditionIdIndexMap,
vector<bool>& stack,
- vector<ConditionState>& initialConditionCache) {
+ vector<ConditionState>& conditionCache) {
VLOG("Combination predicate init() %lld", (long long)mConditionId);
if (mInitialized) {
+ // All the children are guaranteed to be initialized, but the recursion is needed to
+ // fill the conditionCache properly, since another combination condition or metric
+ // might rely on this. The recursion is needed to compute the current condition.
+
+ // Init is called instead of isConditionMet so that the ConditionKey can be filled with the
+ // default key for sliced conditions, since we do not know all indirect descendants here.
+ for (const int childIndex : mChildren) {
+ if (conditionCache[childIndex] == ConditionState::kNotEvaluated) {
+ allConditionTrackers[childIndex]->init(allConditionConfig, allConditionTrackers,
+ conditionIdIndexMap, stack, conditionCache);
+ }
+ }
+ conditionCache[mIndex] =
+ evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache);
return true;
}
@@ -74,9 +88,8 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf
return false;
}
- bool initChildSucceeded =
- childTracker->init(allConditionConfig, allConditionTrackers, conditionIdIndexMap,
- stack, initialConditionCache);
+ bool initChildSucceeded = childTracker->init(allConditionConfig, allConditionTrackers,
+ conditionIdIndexMap, stack, conditionCache);
if (!initChildSucceeded) {
ALOGW("Child initialization failed %lld ", (long long)child);
@@ -96,10 +109,10 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf
childTracker->getAtomMatchingTrackerIndex().end());
}
- mUnSlicedPartCondition = evaluateCombinationCondition(mUnSlicedChildren, mLogicalOperation,
- initialConditionCache);
- initialConditionCache[mIndex] =
- evaluateCombinationCondition(mChildren, mLogicalOperation, initialConditionCache);
+ mUnSlicedPartCondition =
+ evaluateCombinationCondition(mUnSlicedChildren, mLogicalOperation, conditionCache);
+ conditionCache[mIndex] =
+ evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache);
// unmark this node in the recursion stack.
stack[mIndex] = false;
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index 39ff0ab03266..a7fac3deaabe 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -33,7 +33,7 @@ public:
bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack,
- std::vector<ConditionState>& initialConditionCache) override;
+ std::vector<ConditionState>& conditionCache) override;
void evaluateCondition(const LogEvent& event,
const std::vector<MatchingState>& eventMatcherValues,
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index 9da1af427e5f..4e1253506be7 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -46,17 +46,19 @@ public:
// Initialize this ConditionTracker. This initialization is done recursively (DFS). It can also
// be done in the constructor, but we do it separately because (1) easy to return a bool to
// indicate whether the initialization is successful. (2) makes unit test easier.
+ // This function can also be called on config updates, in which case it does nothing other than
+ // fill the condition cache with the current condition.
// allConditionConfig: the list of all Predicate config from statsd_config.
// allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
// need to call init() on children conditions)
// conditionIdIndexMap: the mapping from condition id to its index.
// stack: a bit map to keep track which nodes have been visited on the stack in the recursion.
- // initialConditionCache: tracks initial conditions of all ConditionTrackers.
+ // conditionCache: tracks initial conditions of all ConditionTrackers. returns the
+ // current condition if called on a config update.
virtual bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
const std::unordered_map<int64_t, int>& conditionIdIndexMap,
- std::vector<bool>& stack,
- std::vector<ConditionState>& initialConditionCache) = 0;
+ std::vector<bool>& stack, std::vector<ConditionState>& conditionCache) = 0;
// evaluate current condition given the new event.
// event: the new log event
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index efb4d4989425..f45759b6a77e 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -95,11 +95,14 @@ SimpleConditionTracker::~SimpleConditionTracker() {
bool SimpleConditionTracker::init(const vector<Predicate>& allConditionConfig,
const vector<sp<ConditionTracker>>& allConditionTrackers,
const unordered_map<int64_t, int>& conditionIdIndexMap,
- vector<bool>& stack,
- vector<ConditionState>& initialConditionCache) {
+ vector<bool>& stack, vector<ConditionState>& conditionCache) {
// SimpleConditionTracker does not have dependency on other conditions, thus we just return
// if the initialization was successful.
- initialConditionCache[mIndex] = mInitialValue;
+ ConditionKey conditionKey;
+ if (mSliced) {
+ conditionKey[mConditionId] = DEFAULT_DIMENSION_KEY;
+ }
+ isConditionMet(conditionKey, allConditionTrackers, mSliced, conditionCache);
return mInitialized;
}
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index ea7f87bde2b8..1a9e35e38207 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -38,7 +38,7 @@ public:
bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack,
- std::vector<ConditionState>& initialConditionCache) override;
+ std::vector<ConditionState>& conditionCache) override;
void evaluateCondition(const LogEvent& event,
const std::vector<MatchingState>& eventMatcherValues,
diff --git a/cmds/statsd/src/matchers/AtomMatchingTracker.h b/cmds/statsd/src/matchers/AtomMatchingTracker.h
index 5194f9970766..c1384972464c 100644
--- a/cmds/statsd/src/matchers/AtomMatchingTracker.h
+++ b/cmds/statsd/src/matchers/AtomMatchingTracker.h
@@ -52,6 +52,15 @@ public:
const std::unordered_map<int64_t, int>& matcherMap,
std::vector<bool>& stack) = 0;
+ // Update appropriate state on config updates. Primarily, all indices need to be updated.
+ // This matcher and all of its children are guaranteed to be preserved across the update.
+ // matcher: the AtomMatcher proto from the config.
+ // index: the index of this matcher in mAllAtomMatchingTrackers.
+ // atomMatchingTrackerMap: map from matcher id to index in mAllAtomMatchingTrackers
+ virtual bool onConfigUpdated(
+ const AtomMatcher& matcher, const int index,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap) = 0;
+
// Called when a log event comes.
// event: the log event.
// allAtomMatchingTrackers: the list of all AtomMatchingTrackers. This is needed because the log
@@ -83,7 +92,7 @@ protected:
const int64_t mId;
// Index of this AtomMatchingTracker in MetricsManager's container.
- const int mIndex;
+ int mIndex;
// Whether this AtomMatchingTracker has been properly initialized.
bool mInitialized;
diff --git a/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.cpp b/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.cpp
index 19637a449c44..45685ce5bfee 100644
--- a/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.cpp
@@ -93,6 +93,23 @@ bool CombinationAtomMatchingTracker::init(
return true;
}
+bool CombinationAtomMatchingTracker::onConfigUpdated(
+ const AtomMatcher& matcher, const int index,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap) {
+ mIndex = index;
+ mChildren.clear();
+ AtomMatcher_Combination combinationMatcher = matcher.combination();
+ for (const int64_t child : combinationMatcher.matcher()) {
+ const auto& pair = atomMatchingTrackerMap.find(child);
+ if (pair == atomMatchingTrackerMap.end()) {
+ ALOGW("Matcher %lld not found in the config", (long long)child);
+ return false;
+ }
+ mChildren.push_back(pair->second);
+ }
+ return true;
+}
+
void CombinationAtomMatchingTracker::onLogEvent(
const LogEvent& event, const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
vector<MatchingState>& matcherResults) {
diff --git a/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.h b/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.h
index 06a4932804f5..3160448b6c76 100644
--- a/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.h
+++ b/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.h
@@ -27,7 +27,7 @@ namespace os {
namespace statsd {
// Represents a AtomMatcher_Combination in the StatsdConfig.
-class CombinationAtomMatchingTracker : public virtual AtomMatchingTracker {
+class CombinationAtomMatchingTracker : public AtomMatchingTracker {
public:
CombinationAtomMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash);
@@ -35,6 +35,9 @@ public:
const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
const std::unordered_map<int64_t, int>& matcherMap, std::vector<bool>& stack);
+ bool onConfigUpdated(const AtomMatcher& matcher, const int index,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap) override;
+
~CombinationAtomMatchingTracker();
void onLogEvent(const LogEvent& event,
@@ -45,6 +48,8 @@ private:
LogicalOperation mLogicalOperation;
std::vector<int> mChildren;
+
+ FRIEND_TEST(ConfigUpdateTest, TestUpdateMatchers);
};
} // namespace statsd
diff --git a/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.cpp
index 86b148dd8657..423da5bd3cf8 100644
--- a/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.cpp
@@ -50,6 +50,14 @@ bool SimpleAtomMatchingTracker::init(const vector<AtomMatcher>& allAtomMatchers,
return mInitialized;
}
+bool SimpleAtomMatchingTracker::onConfigUpdated(
+ const AtomMatcher& matcher, const int index,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap) {
+ mIndex = index;
+ // Do not need to update mMatcher since the matcher must be identical across the update.
+ return mInitialized;
+}
+
void SimpleAtomMatchingTracker::onLogEvent(
const LogEvent& event, const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
vector<MatchingState>& matcherResults) {
diff --git a/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.h b/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.h
index 49cbe09f8482..b67e6c20e8f1 100644
--- a/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.h
+++ b/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.h
@@ -28,7 +28,7 @@ namespace android {
namespace os {
namespace statsd {
-class SimpleAtomMatchingTracker : public virtual AtomMatchingTracker {
+class SimpleAtomMatchingTracker : public AtomMatchingTracker {
public:
SimpleAtomMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash,
const SimpleAtomMatcher& matcher, const sp<UidMap>& uidMap);
@@ -40,6 +40,9 @@ public:
const std::unordered_map<int64_t, int>& matcherMap,
std::vector<bool>& stack) override;
+ bool onConfigUpdated(const AtomMatcher& matcher, const int index,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap) override;
+
void onLogEvent(const LogEvent& event,
const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
std::vector<MatchingState>& matcherResults) override;
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
index a9ae5a4e854d..0983dc0b2c83 100644
--- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
@@ -148,8 +148,13 @@ bool updateAtomTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
(long long)id);
return false;
}
- const int oldIndex = oldAtomMatchingTrackerIt->second;
- newAtomMatchingTrackers.push_back(oldAtomMatchingTrackers[oldIndex]);
+ const sp<AtomMatchingTracker>& tracker =
+ oldAtomMatchingTrackers[oldAtomMatchingTrackerIt->second];
+ if (!tracker->onConfigUpdated(matcherProtos[i], i, newAtomMatchingTrackerMap)) {
+ ALOGW("Config update failed for matcher %lld", (long long)id);
+ return false;
+ }
+ newAtomMatchingTrackers.push_back(tracker);
break;
}
case UPDATE_REPLACE: {
diff --git a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
index daf67e93557c..e40fbdb250f1 100644
--- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
@@ -303,8 +303,7 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config,
const int conditionTrackerCount = config.predicate_size();
conditionConfigs.reserve(conditionTrackerCount);
allConditionTrackers.reserve(conditionTrackerCount);
- initialConditionCache.reserve(conditionTrackerCount);
- std::fill(initialConditionCache.begin(), initialConditionCache.end(), ConditionState::kUnknown);
+ initialConditionCache.assign(conditionTrackerCount, ConditionState::kNotEvaluated);
for (int i = 0; i < conditionTrackerCount; i++) {
const Predicate& condition = config.predicate(i);
diff --git a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
index f6d30618ee15..8c698eb15d8d 100644
--- a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
+++ b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
@@ -23,6 +23,7 @@
#include <vector>
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "src/matchers/CombinationAtomMatchingTracker.h"
#include "src/metrics/parsing_utils/metrics_manager_util.h"
#include "tests/statsd_test_util.h"
@@ -370,13 +371,40 @@ TEST_F(ConfigUpdateTest, TestUpdateMatchers) {
EXPECT_NE(oldAtomMatchingTrackers[oldAtomMatchingTrackerMap.at(combination2Id)],
newAtomMatchingTrackers[newAtomMatchingTrackerMap.at(combination2Id)]);
- // Validation, make sure the matchers have the proper ids. Could do more checks here.
+ // Validation, make sure the matchers have the proper ids/indices. Could do more checks here.
EXPECT_EQ(newAtomMatchingTrackers[0]->getId(), combination3Id);
+ EXPECT_EQ(newAtomMatchingTrackers[0]->mIndex, 0);
EXPECT_EQ(newAtomMatchingTrackers[1]->getId(), simple2Id);
+ EXPECT_EQ(newAtomMatchingTrackers[1]->mIndex, 1);
EXPECT_EQ(newAtomMatchingTrackers[2]->getId(), combination2Id);
+ EXPECT_EQ(newAtomMatchingTrackers[2]->mIndex, 2);
EXPECT_EQ(newAtomMatchingTrackers[3]->getId(), simple1Id);
+ EXPECT_EQ(newAtomMatchingTrackers[3]->mIndex, 3);
EXPECT_EQ(newAtomMatchingTrackers[4]->getId(), simple4Id);
+ EXPECT_EQ(newAtomMatchingTrackers[4]->mIndex, 4);
EXPECT_EQ(newAtomMatchingTrackers[5]->getId(), combination1Id);
+ EXPECT_EQ(newAtomMatchingTrackers[5]->mIndex, 5);
+
+ // Verify child indices of Combination Matchers are correct.
+ CombinationAtomMatchingTracker* combinationTracker1 =
+ static_cast<CombinationAtomMatchingTracker*>(newAtomMatchingTrackers[5].get());
+ vector<int>* childMatchers = &combinationTracker1->mChildren;
+ EXPECT_EQ(childMatchers->size(), 1);
+ EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 3), childMatchers->end());
+
+ CombinationAtomMatchingTracker* combinationTracker2 =
+ static_cast<CombinationAtomMatchingTracker*>(newAtomMatchingTrackers[2].get());
+ childMatchers = &combinationTracker2->mChildren;
+ EXPECT_EQ(childMatchers->size(), 2);
+ EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 1), childMatchers->end());
+ EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 3), childMatchers->end());
+
+ CombinationAtomMatchingTracker* combinationTracker3 =
+ static_cast<CombinationAtomMatchingTracker*>(newAtomMatchingTrackers[0].get());
+ childMatchers = &combinationTracker3->mChildren;
+ EXPECT_EQ(childMatchers->size(), 2);
+ EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 1), childMatchers->end());
+ EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 4), childMatchers->end());
}
} // namespace statsd
diff --git a/cmds/uinput/Android.bp b/cmds/uinput/Android.bp
new file mode 100644
index 000000000000..0d7fed2a15c7
--- /dev/null
+++ b/cmds/uinput/Android.bp
@@ -0,0 +1,18 @@
+// Copyright 2020 The Android Open Source Project
+//
+
+java_binary {
+ name: "uinput",
+ wrapper: "uinput",
+ srcs: ["**/*.java",
+ ":uinputcommand_aidl"
+ ],
+ required: ["libuinputcommand_jni"],
+}
+
+filegroup {
+ name: "uinputcommand_aidl",
+ srcs: [
+ "src/com/android/commands/uinput/InputAbsInfo.aidl",
+ ],
+} \ No newline at end of file
diff --git a/cmds/uinput/MODULE_LICENSE_APACHE2 b/cmds/uinput/MODULE_LICENSE_APACHE2
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/cmds/uinput/MODULE_LICENSE_APACHE2
diff --git a/cmds/uinput/NOTICE b/cmds/uinput/NOTICE
new file mode 100644
index 000000000000..c5b1efa7aac7
--- /dev/null
+++ b/cmds/uinput/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/cmds/uinput/README.md b/cmds/uinput/README.md
new file mode 100644
index 000000000000..47e1dad9ccd6
--- /dev/null
+++ b/cmds/uinput/README.md
@@ -0,0 +1,166 @@
+# Usage
+## Two options to use the uinput command:
+### 1. Interactive through stdin:
+type `uinput -` into the terminal, then type/paste commands to send to the binary.
+Use Ctrl+D to signal end of stream to the binary (EOF).
+
+This mode can be also used from an app to send uinput events.
+For an example, see the cts test case at: [InputTestCase.java][2]
+
+When using another program to control uinput in interactive mode, registering a
+new input device (for example, a bluetooth joystick) should be the first step.
+After the device is added, you need to wait for the _onInputDeviceAdded_
+(see [InputDeviceListener][1]) notification before issuing commands
+to the device.
+Failure to do so will cause missed events and inconsistent behavior.
+
+### 2. Using a file as an input:
+type `uinput <filename>`, and the file will be used an an input to the binary.
+You must add a sufficient delay after a "register" command to ensure device
+is ready. The interactive mode is the recommended method of communicating
+with the uinput binary.
+
+All of the input commands should be in pseudo-JSON format as documented below.
+See examples [here][3].
+
+The file can have multiple commands one after the other (which is not strictly
+legal JSON format, as this would imply multiple root elements).
+
+## Command description
+
+1. `register`
+Register a new uinput device
+
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| id | integer | Device id |
+| command | string | Must be set to "register" |
+| name | string | Device name |
+| vid | 16-bit integer| Vendor id |
+| pid | 16-bit integer| Product id |
+| bus | string | Bus that device should use |
+| configuration | int array | uinput device configuration|
+| ff_effects_max| integer | ff_effects_max value |
+| abs_info | array | ABS axes information |
+
+Device ID is used for matching the subsequent commands to a specific device
+to avoid ambiguity when multiple devices are registered.
+
+Device bus is used to determine how the uinput device is connected to the host.
+The options are "usb" and "bluetooth".
+
+Device configuration is used to configure uinput device. "type" field provides the UI_SET_*
+control code, and data is a vector of control values to be sent to uinput device, depends on
+the control code.
+
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| type | integer | UI_SET_ control type |
+| data | int array | control values |
+
+Device ff_effects_max must be provided if FFBIT is set.
+
+Device abs_info fields are provided to set the device axes information. It is an array of below
+objects:
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| code | integer | Axis code |
+| info | object | ABS information object |
+
+ABS information object is defined as below:
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| value | integer | Latest reported value |
+| minimum | integer | Minimum value for the axis |
+| maximum | integer | Maximum value for the axis |
+| fuzz | integer | fuzz value for noise filter|
+| flat | integer | values to be discarded |
+| resolution | integer | resolution of axis |
+
+See [struct input_absinfo][4]) definitions.
+
+Example:
+```json
+
+{
+ "id": 1,
+ "command": "register",
+ "name": "Keyboard (Test)",
+ "vid": 0x18d2,
+ "pid": 0x2c42,
+ "bus": "usb",
+ "configuration":[
+ {"type":100, "data":[1, 21]}, // UI_SET_EVBIT : EV_KEY and EV_FF
+ {"type":101, "data":[11, 2, 3, 4]}, // UI_SET_KEYBIT : KEY_0 KEY_1 KEY_2 KEY_3
+ {"type":107, "data":[80]} // UI_SET_FFBIT : FF_RUMBLE
+ ],
+ "ff_effects_max" : 1,
+ "abs_info": [
+ {"code":1, "info": {"value":20, "minimum":-255,
+ "maximum":255, "fuzz":0, "flat":0, "resolution":1}
+ },
+ {"code":8, "info": {"value":-50, "minimum":-255,
+ "maximum":255, "fuzz":0, "flat":0, "resolution":1}
+ }
+ ]
+}
+
+```
+2. `delay`
+Add a delay to command processing
+
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| id | integer | Device id |
+| command | string | Must be set to "delay" |
+| duration | integer | Delay in milliseconds |
+
+Example:
+```json
+{
+ "id": 1,
+ "command": "delay",
+ "duration": 10
+}
+```
+
+3. `inject`
+Send an array of uinput event packets [type, code, value] to the uinput device
+
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| id | integer | Device id |
+| command | string | Must be set to "inject" |
+| events | integer array | events to inject |
+
+The "events" parameter is an array of integers, encapsulates evdev input_event type, code and value,
+see the example below.
+
+Example:
+```json
+{
+ "id": 1,
+ "command": "inject",
+ "events": [0x01, 0xb, 0x1, // EV_KEY, KEY_0, DOWN
+ 0x00, 0x00, 0x00, // EV_SYN, SYN_REPORT, 0
+ 0x01, 0x0b, 0x00, // EV_KEY, KEY_0, UP
+ 0x00, 0x00, 0x00, // EV_SYN, SYN_REPORT, 0
+ 0x01, 0x2, 0x1, // EV_KEY, KEY_1, DOWN
+ 0x00, 0x00, 0x01, // EV_SYN, SYN_REPORT, 0
+ 0x01, 0x02, 0x00, // EV_KEY, KEY_1, UP
+ 0x00, 0x00, 0x01 // EV_SYN, SYN_REPORT, 0
+ ]
+}
+```
+
+### Notes
+1. As soon as EOF is reached (either in interactive mode, or in file mode),
+the device that was created will be unregistered. There is no
+explicit command for unregistering a device.
+2. The `getevent` utility can used to print out the key events
+for debugging purposes.
+
+[1]: https://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
+[2]: ../../../../cts/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
+[3]: ../../../../cts/tests/tests/hardware/res/raw/
+[4]: ../../../../bionic/libc/kernel/uapi/linux/input.h
diff --git a/cmds/uinput/jni/Android.bp b/cmds/uinput/jni/Android.bp
new file mode 100644
index 000000000000..199bbbd35274
--- /dev/null
+++ b/cmds/uinput/jni/Android.bp
@@ -0,0 +1,23 @@
+cc_library_shared {
+ name: "libuinputcommand_jni",
+
+ srcs: [
+ "com_android_commands_uinput_Device.cpp",
+ ":uinputcommand_aidl",
+ ],
+
+ shared_libs: [
+ "libandroid",
+ "libandroid_runtime_lazy",
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libnativehelper",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+}
diff --git a/cmds/uinput/jni/com_android_commands_uinput_Device.cpp b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
new file mode 100644
index 000000000000..06fa2aac2c7e
--- /dev/null
+++ b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
@@ -0,0 +1,351 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "UinputCommandDevice"
+
+#include <linux/uinput.h>
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <time.h>
+#include <unistd.h>
+#include <algorithm>
+#include <array>
+#include <cstdio>
+#include <cstring>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include <android/looper.h>
+#include <android_os_Parcel.h>
+#include <jni.h>
+#include <log/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
+
+#include <android-base/stringprintf.h>
+
+#include "com_android_commands_uinput_Device.h"
+
+namespace android {
+namespace uinput {
+
+using src::com::android::commands::uinput::InputAbsInfo;
+
+static constexpr const char* UINPUT_PATH = "/dev/uinput";
+
+static struct {
+ jmethodID onDeviceConfigure;
+ jmethodID onDeviceVibrating;
+ jmethodID onDeviceError;
+} gDeviceCallbackClassInfo;
+
+static void checkAndClearException(JNIEnv* env, const char* methodName) {
+ if (env->ExceptionCheck()) {
+ ALOGE("An exception was thrown by callback '%s'.", methodName);
+ env->ExceptionClear();
+ }
+}
+
+DeviceCallback::DeviceCallback(JNIEnv* env, jobject callback)
+ : mCallbackObject(env->NewGlobalRef(callback)) {
+ env->GetJavaVM(&mJavaVM);
+}
+
+DeviceCallback::~DeviceCallback() {
+ JNIEnv* env = getJNIEnv();
+ env->DeleteGlobalRef(mCallbackObject);
+}
+
+void DeviceCallback::onDeviceError() {
+ JNIEnv* env = getJNIEnv();
+ env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceError);
+ checkAndClearException(env, "onDeviceError");
+}
+
+void DeviceCallback::onDeviceConfigure(int handle) {
+ JNIEnv* env = getJNIEnv();
+ env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceConfigure, handle);
+ checkAndClearException(env, "onDeviceConfigure");
+}
+
+void DeviceCallback::onDeviceVibrating(int value) {
+ JNIEnv* env = getJNIEnv();
+ env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceVibrating, value);
+ checkAndClearException(env, "onDeviceVibrating");
+}
+
+JNIEnv* DeviceCallback::getJNIEnv() {
+ JNIEnv* env;
+ mJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+ return env;
+}
+
+std::unique_ptr<UinputDevice> UinputDevice::open(int32_t id, const char* name, int32_t vid,
+ int32_t pid, uint16_t bus, uint32_t ffEffectsMax,
+ std::unique_ptr<DeviceCallback> callback) {
+ android::base::unique_fd fd(::open(UINPUT_PATH, O_RDWR | O_NONBLOCK | O_CLOEXEC));
+ if (!fd.ok()) {
+ ALOGE("Failed to open uinput: %s", strerror(errno));
+ return nullptr;
+ }
+
+ int32_t version;
+ ::ioctl(fd, UI_GET_VERSION, &version);
+ if (version < 5) {
+ ALOGE("Kernel version %d older than 5 is not supported", version);
+ return nullptr;
+ }
+
+ struct uinput_setup setupDescriptor;
+ memset(&setupDescriptor, 0, sizeof(setupDescriptor));
+ strlcpy(setupDescriptor.name, name, UINPUT_MAX_NAME_SIZE);
+ setupDescriptor.id.version = 1;
+ setupDescriptor.id.bustype = bus;
+ setupDescriptor.id.vendor = vid;
+ setupDescriptor.id.product = pid;
+ setupDescriptor.ff_effects_max = ffEffectsMax;
+
+ // Request device configuration.
+ callback->onDeviceConfigure(fd.get());
+
+ // register the input device
+ if (::ioctl(fd, UI_DEV_SETUP, &setupDescriptor)) {
+ ALOGE("UI_DEV_SETUP ioctl failed on fd %d: %s.", fd.get(), strerror(errno));
+ return nullptr;
+ }
+
+ if (::ioctl(fd, UI_DEV_CREATE) != 0) {
+ ALOGE("Unable to create uinput device: %s.", strerror(errno));
+ return nullptr;
+ }
+
+ // using 'new' to access non-public constructor
+ return std::unique_ptr<UinputDevice>(new UinputDevice(id, std::move(fd), std::move(callback)));
+}
+
+UinputDevice::UinputDevice(int32_t id, android::base::unique_fd fd,
+ std::unique_ptr<DeviceCallback> callback)
+ : mId(id), mFd(std::move(fd)), mDeviceCallback(std::move(callback)) {
+ ALooper* aLooper = ALooper_forThread();
+ if (aLooper == nullptr) {
+ ALOGE("Could not get ALooper, ALooper_forThread returned NULL");
+ aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
+ }
+ ALooper_addFd(
+ aLooper, mFd, 0, ALOOPER_EVENT_INPUT,
+ [](int, int events, void* data) {
+ UinputDevice* d = reinterpret_cast<UinputDevice*>(data);
+ return d->handleEvents(events);
+ },
+ reinterpret_cast<void*>(this));
+ ALOGI("uinput device %d created: version = %d, fd = %d", mId, UINPUT_VERSION, mFd.get());
+}
+
+UinputDevice::~UinputDevice() {
+ ::ioctl(mFd, UI_DEV_DESTROY);
+}
+
+void UinputDevice::injectEvent(uint16_t type, uint16_t code, int32_t value) {
+ struct input_event event = {};
+ event.type = type;
+ event.code = code;
+ event.value = value;
+ timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ TIMESPEC_TO_TIMEVAL(&event.time, &ts);
+
+ if (::write(mFd, &event, sizeof(input_event)) < 0) {
+ ALOGE("Could not write event %" PRIu16 " %" PRIu16 " with value %" PRId32 " : %s", type,
+ code, value, strerror(errno));
+ }
+}
+
+int UinputDevice::handleEvents(int events) {
+ if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
+ ALOGE("uinput node was closed or an error occurred. events=0x%x", events);
+ mDeviceCallback->onDeviceError();
+ return 0;
+ }
+ struct input_event ev;
+ ssize_t ret = ::read(mFd, &ev, sizeof(ev));
+ if (ret < 0) {
+ ALOGE("Failed to read from uinput node: %s", strerror(errno));
+ mDeviceCallback->onDeviceError();
+ return 0;
+ }
+
+ switch (ev.type) {
+ case EV_UINPUT: {
+ if (ev.code == UI_FF_UPLOAD) {
+ struct uinput_ff_upload ff_upload;
+ ff_upload.request_id = ev.value;
+ ::ioctl(mFd, UI_BEGIN_FF_UPLOAD, &ff_upload);
+ ff_upload.retval = 0;
+ ::ioctl(mFd, UI_END_FF_UPLOAD, &ff_upload);
+ } else if (ev.code == UI_FF_ERASE) {
+ struct uinput_ff_erase ff_erase;
+ ff_erase.request_id = ev.value;
+ ::ioctl(mFd, UI_BEGIN_FF_ERASE, &ff_erase);
+ ff_erase.retval = 0;
+ ::ioctl(mFd, UI_END_FF_ERASE, &ff_erase);
+ }
+ break;
+ }
+ case EV_FF: {
+ ALOGI("EV_FF effect = %d value = %d", ev.code, ev.value);
+ mDeviceCallback->onDeviceVibrating(ev.value);
+ break;
+ }
+ default: {
+ ALOGI("Unhandled event type: %" PRIu32, ev.type);
+ break;
+ }
+ }
+
+ return 1;
+}
+
+} // namespace uinput
+
+std::vector<int32_t> toVector(JNIEnv* env, jintArray javaArray) {
+ std::vector<int32_t> data;
+ if (javaArray == nullptr) {
+ return data;
+ }
+
+ ScopedIntArrayRO scopedArray(env, javaArray);
+ size_t size = scopedArray.size();
+ data.reserve(size);
+ for (size_t i = 0; i < size; i++) {
+ data.push_back(static_cast<int32_t>(scopedArray[i]));
+ }
+ return data;
+}
+
+static jlong openUinputDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid,
+ jint pid, jint bus, jint ffEffectsMax, jobject callback) {
+ ScopedUtfChars name(env, rawName);
+ if (name.c_str() == nullptr) {
+ return 0;
+ }
+
+ std::unique_ptr<uinput::DeviceCallback> cb =
+ std::make_unique<uinput::DeviceCallback>(env, callback);
+
+ std::unique_ptr<uinput::UinputDevice> d =
+ uinput::UinputDevice::open(id, name.c_str(), vid, pid, bus, ffEffectsMax,
+ std::move(cb));
+ return reinterpret_cast<jlong>(d.release());
+}
+
+static void closeUinputDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
+ uinput::UinputDevice* d = reinterpret_cast<uinput::UinputDevice*>(ptr);
+ if (d != nullptr) {
+ delete d;
+ }
+}
+
+static void injectEvent(JNIEnv* /* env */, jclass /* clazz */, jlong ptr, jint type, jint code,
+ jint value) {
+ uinput::UinputDevice* d = reinterpret_cast<uinput::UinputDevice*>(ptr);
+ if (d != nullptr) {
+ d->injectEvent(static_cast<uint16_t>(type), static_cast<uint16_t>(code),
+ static_cast<int32_t>(value));
+ } else {
+ ALOGE("Could not inject event, Device* is null!");
+ }
+}
+
+static void configure(JNIEnv* env, jclass /* clazz */, jint handle, jint code,
+ jintArray rawConfigs) {
+ std::vector<int32_t> configs = toVector(env, rawConfigs);
+ // Configure uinput device, with user specified code and value.
+ for (auto& config : configs) {
+ ::ioctl(static_cast<int>(handle), _IOW(UINPUT_IOCTL_BASE, code, int), config);
+ }
+}
+
+static void setAbsInfo(JNIEnv* env, jclass /* clazz */, jint handle, jint axisCode,
+ jobject infoObj) {
+ Parcel* parcel = parcelForJavaObject(env, infoObj);
+ uinput::InputAbsInfo info;
+
+ info.readFromParcel(parcel);
+
+ struct uinput_abs_setup absSetup;
+ absSetup.code = axisCode;
+ absSetup.absinfo.maximum = info.maximum;
+ absSetup.absinfo.minimum = info.minimum;
+ absSetup.absinfo.value = info.value;
+ absSetup.absinfo.fuzz = info.fuzz;
+ absSetup.absinfo.flat = info.flat;
+ absSetup.absinfo.resolution = info.resolution;
+
+ ::ioctl(static_cast<int>(handle), UI_ABS_SETUP, &absSetup);
+}
+
+static JNINativeMethod sMethods[] = {
+ {"nativeOpenUinputDevice",
+ "(Ljava/lang/String;IIIII"
+ "Lcom/android/commands/uinput/Device$DeviceCallback;)J",
+ reinterpret_cast<void*>(openUinputDevice)},
+ {"nativeInjectEvent", "(JIII)V", reinterpret_cast<void*>(injectEvent)},
+ {"nativeConfigure", "(II[I)V", reinterpret_cast<void*>(configure)},
+ {"nativeSetAbsInfo", "(IILandroid/os/Parcel;)V", reinterpret_cast<void*>(setAbsInfo)},
+ {"nativeCloseUinputDevice", "(J)V", reinterpret_cast<void*>(closeUinputDevice)},
+};
+
+int register_com_android_commands_uinput_Device(JNIEnv* env) {
+ jclass clazz = env->FindClass("com/android/commands/uinput/Device$DeviceCallback");
+ if (clazz == nullptr) {
+ ALOGE("Unable to find class 'DeviceCallback'");
+ return JNI_ERR;
+ }
+
+ uinput::gDeviceCallbackClassInfo.onDeviceConfigure =
+ env->GetMethodID(clazz, "onDeviceConfigure", "(I)V");
+ uinput::gDeviceCallbackClassInfo.onDeviceVibrating =
+ env->GetMethodID(clazz, "onDeviceVibrating", "(I)V");
+ uinput::gDeviceCallbackClassInfo.onDeviceError =
+ env->GetMethodID(clazz, "onDeviceError", "()V");
+ if (uinput::gDeviceCallbackClassInfo.onDeviceConfigure == nullptr ||
+ uinput::gDeviceCallbackClassInfo.onDeviceError == nullptr ||
+ uinput::gDeviceCallbackClassInfo.onDeviceVibrating == nullptr) {
+ ALOGE("Unable to obtain onDeviceConfigure or onDeviceError or onDeviceVibrating methods");
+ return JNI_ERR;
+ }
+ return jniRegisterNativeMethods(env, "com/android/commands/uinput/Device", sMethods,
+ NELEM(sMethods));
+}
+
+} // namespace android
+
+jint JNI_OnLoad(JavaVM* jvm, void*) {
+ JNIEnv* env = nullptr;
+ if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) {
+ return JNI_ERR;
+ }
+
+ if (android::register_com_android_commands_uinput_Device(env) < 0) {
+ return JNI_ERR;
+ }
+
+ return JNI_VERSION_1_6;
+}
diff --git a/cmds/uinput/jni/com_android_commands_uinput_Device.h b/cmds/uinput/jni/com_android_commands_uinput_Device.h
new file mode 100644
index 000000000000..5a9a06cfb32e
--- /dev/null
+++ b/cmds/uinput/jni/com_android_commands_uinput_Device.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#include <memory>
+#include <vector>
+
+#include <jni.h>
+#include <linux/input.h>
+
+#include <android-base/unique_fd.h>
+#include "src/com/android/commands/uinput/InputAbsInfo.h"
+
+namespace android {
+namespace uinput {
+
+class DeviceCallback {
+public:
+ DeviceCallback(JNIEnv* env, jobject callback);
+ ~DeviceCallback();
+
+ void onDeviceOpen();
+ void onDeviceGetReport(uint32_t requestId, uint8_t reportId);
+ void onDeviceOutput(const std::vector<uint8_t>& data);
+ void onDeviceConfigure(int handle);
+ void onDeviceVibrating(int value);
+ void onDeviceError();
+
+private:
+ JNIEnv* getJNIEnv();
+ jobject mCallbackObject;
+ JavaVM* mJavaVM;
+};
+
+class UinputDevice {
+public:
+ static std::unique_ptr<UinputDevice> open(int32_t id, const char* name, int32_t vid,
+ int32_t pid, uint16_t bus, uint32_t ff_effects_max,
+ std::unique_ptr<DeviceCallback> callback);
+
+ virtual ~UinputDevice();
+
+ void injectEvent(uint16_t type, uint16_t code, int32_t value);
+ int handleEvents(int events);
+
+private:
+ UinputDevice(int32_t id, android::base::unique_fd fd, std::unique_ptr<DeviceCallback> callback);
+
+ int32_t mId;
+ android::base::unique_fd mFd;
+ std::unique_ptr<DeviceCallback> mDeviceCallback;
+};
+
+} // namespace uinput
+} // namespace android
diff --git a/cmds/uinput/src/com/android/commands/uinput/Device.java b/cmds/uinput/src/com/android/commands/uinput/Device.java
new file mode 100644
index 000000000000..62bee7b964bd
--- /dev/null
+++ b/cmds/uinput/src/com/android/commands/uinput/Device.java
@@ -0,0 +1,232 @@
+/*
+ * 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.commands.uinput;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.os.SomeArgs;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import src.com.android.commands.uinput.InputAbsInfo;
+
+/**
+ * Device class defines uinput device interfaces of device operations, for device open, close,
+ * configuration, events injection.
+ */
+public class Device {
+ private static final String TAG = "UinputDevice";
+
+ private static final int MSG_OPEN_UINPUT_DEVICE = 1;
+ private static final int MSG_CLOSE_UINPUT_DEVICE = 2;
+ private static final int MSG_INJECT_EVENT = 3;
+
+ private final int mId;
+ private final HandlerThread mThread;
+ private final DeviceHandler mHandler;
+ // mConfiguration is sparse array of ioctl code and array of values.
+ private final SparseArray<int[]> mConfiguration;
+ private final SparseArray<InputAbsInfo> mAbsInfo;
+ private final OutputStream mOutputStream;
+ private final Object mCond = new Object();
+ private long mTimeToSend;
+
+ static {
+ System.loadLibrary("uinputcommand_jni");
+ }
+
+ private static native long nativeOpenUinputDevice(String name, int id, int vid, int pid,
+ int bus, int ffEffectsMax, DeviceCallback callback);
+ private static native void nativeCloseUinputDevice(long ptr);
+ private static native void nativeInjectEvent(long ptr, int type, int code, int value);
+ private static native void nativeConfigure(int handle, int code, int[] configs);
+ private static native void nativeSetAbsInfo(int handle, int axisCode, Parcel axisParcel);
+
+ public Device(int id, String name, int vid, int pid, int bus,
+ SparseArray<int[]> configuration, int ffEffectsMax,
+ SparseArray<InputAbsInfo> absInfo) {
+ mId = id;
+ mThread = new HandlerThread("UinputDeviceHandler");
+ mThread.start();
+ mHandler = new DeviceHandler(mThread.getLooper());
+ mConfiguration = configuration;
+ mAbsInfo = absInfo;
+ mOutputStream = System.out;
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = id;
+ args.argi2 = vid;
+ args.argi3 = pid;
+ args.argi4 = bus;
+ args.argi5 = ffEffectsMax;
+ if (name != null) {
+ args.arg1 = name;
+ } else {
+ args.arg1 = id + ":" + vid + ":" + pid;
+ }
+
+ mHandler.obtainMessage(MSG_OPEN_UINPUT_DEVICE, args).sendToTarget();
+ mTimeToSend = SystemClock.uptimeMillis();
+ }
+
+ /**
+ * Inject uinput events to device
+ *
+ * @param events Array of raw uinput events.
+ */
+ public void injectEvent(int[] events) {
+ // if two messages are sent at identical time, they will be processed in order received
+ Message msg = mHandler.obtainMessage(MSG_INJECT_EVENT, events);
+ mHandler.sendMessageAtTime(msg, mTimeToSend);
+ }
+
+ /**
+ * Impose a delay to the device for execution.
+ *
+ * @param delay Time to delay in unit of milliseconds.
+ */
+ public void addDelay(int delay) {
+ mTimeToSend = Math.max(SystemClock.uptimeMillis(), mTimeToSend) + delay;
+ }
+
+ /**
+ * Close an uinput device.
+ *
+ */
+ public void close() {
+ Message msg = mHandler.obtainMessage(MSG_CLOSE_UINPUT_DEVICE);
+ mHandler.sendMessageAtTime(msg, Math.max(SystemClock.uptimeMillis(), mTimeToSend) + 1);
+ try {
+ synchronized (mCond) {
+ mCond.wait();
+ }
+ } catch (InterruptedException ignore) {
+ }
+ }
+
+ private class DeviceHandler extends Handler {
+ private long mPtr;
+ private int mBarrierToken;
+
+ DeviceHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_OPEN_UINPUT_DEVICE:
+ SomeArgs args = (SomeArgs) msg.obj;
+ mPtr = nativeOpenUinputDevice((String) args.arg1, args.argi1, args.argi2,
+ args.argi3, args.argi4, args.argi5,
+ new DeviceCallback());
+ break;
+ case MSG_INJECT_EVENT:
+ if (mPtr != 0) {
+ int[] events = (int[]) msg.obj;
+ for (int pos = 0; pos + 2 < events.length; pos += 3) {
+ nativeInjectEvent(mPtr, events[pos], events[pos + 1], events[pos + 2]);
+ }
+ }
+ break;
+ case MSG_CLOSE_UINPUT_DEVICE:
+ if (mPtr != 0) {
+ nativeCloseUinputDevice(mPtr);
+ getLooper().quitSafely();
+ mPtr = 0;
+ } else {
+ Log.e(TAG, "Tried to close already closed device.");
+ }
+ Log.i(TAG, "Device closed.");
+ synchronized (mCond) {
+ mCond.notify();
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown device message");
+ }
+ }
+
+ public void pauseEvents() {
+ mBarrierToken = getLooper().myQueue().postSyncBarrier();
+ }
+
+ public void resumeEvents() {
+ getLooper().myQueue().removeSyncBarrier(mBarrierToken);
+ mBarrierToken = 0;
+ }
+ }
+
+ private class DeviceCallback {
+ public void onDeviceOpen() {
+ mHandler.resumeEvents();
+ }
+
+ public void onDeviceConfigure(int handle) {
+ for (int i = 0; i < mConfiguration.size(); i++) {
+ int key = mConfiguration.keyAt(i);
+ int[] data = mConfiguration.get(key);
+ nativeConfigure(handle, key, data);
+ }
+
+ if (mAbsInfo != null) {
+ for (int i = 0; i < mAbsInfo.size(); i++) {
+ int key = mAbsInfo.keyAt(i);
+ InputAbsInfo info = mAbsInfo.get(key);
+ Parcel parcel = Parcel.obtain();
+ info.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ nativeSetAbsInfo(handle, key, parcel);
+ }
+ }
+ }
+
+ public void onDeviceVibrating(int value) {
+ JSONObject json = new JSONObject();
+ try {
+ json.put("reason", "vibrating");
+ json.put("id", mId);
+ json.put("status", value);
+ } catch (JSONException e) {
+ throw new RuntimeException("Could not create JSON object ", e);
+ }
+ try {
+ mOutputStream.write(json.toString().getBytes());
+ mOutputStream.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void onDeviceError() {
+ Log.e(TAG, "Device error occurred, closing /dev/uinput");
+ Message msg = mHandler.obtainMessage(MSG_CLOSE_UINPUT_DEVICE);
+ msg.setAsynchronous(true);
+ msg.sendToTarget();
+ }
+ }
+}
diff --git a/cmds/uinput/src/com/android/commands/uinput/Event.java b/cmds/uinput/src/com/android/commands/uinput/Event.java
new file mode 100644
index 000000000000..c4ba05054eda
--- /dev/null
+++ b/cmds/uinput/src/com/android/commands/uinput/Event.java
@@ -0,0 +1,454 @@
+/*
+ * 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.commands.uinput;
+
+import android.util.JsonReader;
+import android.util.JsonToken;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import src.com.android.commands.uinput.InputAbsInfo;
+
+/**
+ * An event is a JSON file defined action event to instruct uinput to perform a command like
+ * device registration or uinput events injection.
+ */
+public class Event {
+ private static final String TAG = "UinputEvent";
+
+ public static final String COMMAND_REGISTER = "register";
+ public static final String COMMAND_DELAY = "delay";
+ public static final String COMMAND_INJECT = "inject";
+ private static final int ABS_CNT = 64;
+
+ // These constants come from "include/uapi/linux/input.h" in the kernel
+ enum Bus {
+ USB(0x03), BLUETOOTH(0x05);
+ private final int mValue;
+
+ Bus(int value) {
+ mValue = value;
+ }
+
+ int getValue() {
+ return mValue;
+ }
+ }
+
+ private int mId;
+ private String mCommand;
+ private String mName;
+ private int mVid;
+ private int mPid;
+ private Bus mBus;
+ private int[] mInjections;
+ private SparseArray<int[]> mConfiguration;
+ private int mDuration;
+ private int mFfEffectsMax = 0;
+ private SparseArray<InputAbsInfo> mAbsInfo;
+
+ public int getId() {
+ return mId;
+ }
+
+ public String getCommand() {
+ return mCommand;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public int getVendorId() {
+ return mVid;
+ }
+
+ public int getProductId() {
+ return mPid;
+ }
+
+ public int getBus() {
+ return mBus.getValue();
+ }
+
+ public int[] getInjections() {
+ return mInjections;
+ }
+
+ public SparseArray<int[]> getConfiguration() {
+ return mConfiguration;
+ }
+
+ public int getDuration() {
+ return mDuration;
+ }
+
+ public int getFfEffectsMax() {
+ return mFfEffectsMax;
+ }
+
+ public SparseArray<InputAbsInfo> getAbsInfo() {
+ return mAbsInfo;
+ }
+
+ /**
+ * Convert an event to String.
+ */
+ public String toString() {
+ return "Event{id=" + mId
+ + ", command=" + mCommand
+ + ", name=" + mName
+ + ", vid=" + mVid
+ + ", pid=" + mPid
+ + ", bus=" + mBus
+ + ", events=" + Arrays.toString(mInjections)
+ + ", configuration=" + mConfiguration
+ + ", duration=" + mDuration
+ + ", ff_effects_max=" + mFfEffectsMax
+ + "}";
+ }
+
+ private static class Builder {
+ private Event mEvent;
+
+ Builder() {
+ mEvent = new Event();
+ }
+
+ public void setId(int id) {
+ mEvent.mId = id;
+ }
+
+ private void setCommand(String command) {
+ mEvent.mCommand = command;
+ }
+
+ public void setName(String name) {
+ mEvent.mName = name;
+ }
+
+ public void setInjections(int[] events) {
+ mEvent.mInjections = events;
+ }
+
+ public void setConfiguration(SparseArray<int[]> configuration) {
+ mEvent.mConfiguration = configuration;
+ }
+
+ public void setVid(int vid) {
+ mEvent.mVid = vid;
+ }
+
+ public void setPid(int pid) {
+ mEvent.mPid = pid;
+ }
+
+ public void setBus(Bus bus) {
+ mEvent.mBus = bus;
+ }
+
+ public void setDuration(int duration) {
+ mEvent.mDuration = duration;
+ }
+
+ public void setFfEffectsMax(int ffEffectsMax) {
+ mEvent.mFfEffectsMax = ffEffectsMax;
+ }
+
+ public void setAbsInfo(SparseArray<InputAbsInfo> absInfo) {
+ mEvent.mAbsInfo = absInfo;
+ }
+
+ public Event build() {
+ if (mEvent.mId == -1) {
+ throw new IllegalStateException("No event id");
+ } else if (mEvent.mCommand == null) {
+ throw new IllegalStateException("Event does not contain a command");
+ }
+ if (COMMAND_REGISTER.equals(mEvent.mCommand)) {
+ if (mEvent.mConfiguration == null) {
+ throw new IllegalStateException(
+ "Device registration is missing configuration");
+ }
+ } else if (COMMAND_DELAY.equals(mEvent.mCommand)) {
+ if (mEvent.mDuration <= 0) {
+ throw new IllegalStateException("Delay has missing or invalid duration");
+ }
+ } else if (COMMAND_INJECT.equals(mEvent.mCommand)) {
+ if (mEvent.mInjections == null) {
+ throw new IllegalStateException("Inject command is missing injection data");
+ }
+ } else {
+ throw new IllegalStateException("Unknown command " + mEvent.mCommand);
+ }
+ return mEvent;
+ }
+ }
+
+ /**
+ * A class that parses the JSON event format from an input stream to build device events.
+ */
+ public static class Reader {
+ private JsonReader mReader;
+
+ public Reader(InputStreamReader in) {
+ mReader = new JsonReader(in);
+ mReader.setLenient(true);
+ }
+
+ /**
+ * Get next event entry from JSON file reader.
+ */
+ public Event getNextEvent() throws IOException {
+ Event e = null;
+ while (e == null && mReader.peek() != JsonToken.END_DOCUMENT) {
+ Event.Builder eb = new Event.Builder();
+ try {
+ mReader.beginObject();
+ while (mReader.hasNext()) {
+ String name = mReader.nextName();
+ switch (name) {
+ case "id":
+ eb.setId(readInt());
+ break;
+ case "command":
+ eb.setCommand(mReader.nextString());
+ break;
+ case "name":
+ eb.setName(mReader.nextString());
+ break;
+ case "vid":
+ eb.setVid(readInt());
+ break;
+ case "pid":
+ eb.setPid(readInt());
+ break;
+ case "bus":
+ eb.setBus(readBus());
+ break;
+ case "events":
+ int[] injections = readIntList().stream()
+ .mapToInt(Integer::intValue).toArray();
+ eb.setInjections(injections);
+ break;
+ case "configuration":
+ eb.setConfiguration(readConfiguration());
+ break;
+ case "ff_effects_max":
+ eb.setFfEffectsMax(readInt());
+ break;
+ case "abs_info":
+ eb.setAbsInfo(readAbsInfoArray());
+ break;
+ case "duration":
+ eb.setDuration(readInt());
+ break;
+ default:
+ mReader.skipValue();
+ }
+ }
+ mReader.endObject();
+ } catch (IllegalStateException ex) {
+ error("Error reading in object, ignoring.", ex);
+ consumeRemainingElements();
+ mReader.endObject();
+ continue;
+ }
+ e = eb.build();
+ }
+
+ return e;
+ }
+
+ private ArrayList<Integer> readIntList() throws IOException {
+ ArrayList<Integer> data = new ArrayList<Integer>();
+ try {
+ mReader.beginArray();
+ while (mReader.hasNext()) {
+ data.add(Integer.decode(mReader.nextString()));
+ }
+ mReader.endArray();
+ } catch (IllegalStateException | NumberFormatException e) {
+ consumeRemainingElements();
+ mReader.endArray();
+ throw new IllegalStateException("Encountered malformed data.", e);
+ }
+ return data;
+ }
+
+ private byte[] readData() throws IOException {
+ ArrayList<Integer> data = readIntList();
+ byte[] rawData = new byte[data.size()];
+ for (int i = 0; i < data.size(); i++) {
+ int d = data.get(i);
+ if ((d & 0xFF) != d) {
+ throw new IllegalStateException("Invalid data, all values must be byte-sized");
+ }
+ rawData[i] = (byte) d;
+ }
+ return rawData;
+ }
+
+ private int readInt() throws IOException {
+ String val = mReader.nextString();
+ return Integer.decode(val);
+ }
+
+ private Bus readBus() throws IOException {
+ String val = mReader.nextString();
+ return Bus.valueOf(val.toUpperCase());
+ }
+
+ private SparseArray<int[]> readConfiguration()
+ throws IllegalStateException, IOException {
+ SparseArray<int[]> configuration = new SparseArray<>();
+ try {
+ mReader.beginArray();
+ while (mReader.hasNext()) {
+ int type = 0;
+ int[] data = null;
+ mReader.beginObject();
+ while (mReader.hasNext()) {
+ String name = mReader.nextName();
+ switch (name) {
+ case "type":
+ type = readInt();
+ break;
+ case "data":
+ data = readIntList().stream()
+ .mapToInt(Integer::intValue).toArray();
+ break;
+ default:
+ consumeRemainingElements();
+ mReader.endObject();
+ throw new IllegalStateException(
+ "Invalid key in device configuration: " + name);
+ }
+ }
+ mReader.endObject();
+ if (data != null) {
+ configuration.put(type, data);
+ }
+ }
+ mReader.endArray();
+ } catch (IllegalStateException | NumberFormatException e) {
+ consumeRemainingElements();
+ mReader.endArray();
+ throw new IllegalStateException("Encountered malformed data.", e);
+ }
+ return configuration;
+ }
+
+ private InputAbsInfo readAbsInfo() throws IllegalStateException, IOException {
+ InputAbsInfo absInfo = new InputAbsInfo();
+ try {
+ mReader.beginObject();
+ while (mReader.hasNext()) {
+ String name = mReader.nextName();
+ switch (name) {
+ case "value":
+ absInfo.value = readInt();
+ break;
+ case "minimum":
+ absInfo.minimum = readInt();
+ break;
+ case "maximum":
+ absInfo.maximum = readInt();
+ break;
+ case "fuzz":
+ absInfo.fuzz = readInt();
+ break;
+ case "flat":
+ absInfo.flat = readInt();
+ break;
+ case "resolution":
+ absInfo.resolution = readInt();
+ break;
+ default:
+ consumeRemainingElements();
+ mReader.endObject();
+ throw new IllegalStateException("Invalid key in abs info: " + name);
+ }
+ }
+ mReader.endObject();
+ } catch (IllegalStateException | NumberFormatException e) {
+ consumeRemainingElements();
+ mReader.endObject();
+ throw new IllegalStateException("Encountered malformed data.", e);
+ }
+ return absInfo;
+ }
+
+ private SparseArray<InputAbsInfo> readAbsInfoArray()
+ throws IllegalStateException, IOException {
+ SparseArray<InputAbsInfo> infoArray = new SparseArray<>();
+ try {
+ mReader.beginArray();
+ while (mReader.hasNext()) {
+ int type = 0;
+ InputAbsInfo absInfo = null;
+ mReader.beginObject();
+ while (mReader.hasNext()) {
+ String name = mReader.nextName();
+ switch (name) {
+ case "code":
+ type = readInt();
+ break;
+ case "info":
+ absInfo = readAbsInfo();
+ break;
+ default:
+ consumeRemainingElements();
+ mReader.endObject();
+ throw new IllegalStateException("Invalid key in abs info array: "
+ + name);
+ }
+ }
+ mReader.endObject();
+ if (absInfo != null) {
+ infoArray.put(type, absInfo);
+ }
+ }
+ mReader.endArray();
+ } catch (IllegalStateException | NumberFormatException e) {
+ consumeRemainingElements();
+ mReader.endArray();
+ throw new IllegalStateException("Encountered malformed data.", e);
+ }
+ return infoArray;
+ }
+
+ private void consumeRemainingElements() throws IOException {
+ while (mReader.hasNext()) {
+ mReader.skipValue();
+ }
+ }
+ }
+
+ private static void error(String msg, Exception e) {
+ System.out.println(msg);
+ Log.e(TAG, msg);
+ if (e != null) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ }
+ }
+}
diff --git a/cmds/uinput/src/com/android/commands/uinput/InputAbsInfo.aidl b/cmds/uinput/src/com/android/commands/uinput/InputAbsInfo.aidl
new file mode 100644
index 000000000000..88c57f2c8965
--- /dev/null
+++ b/cmds/uinput/src/com/android/commands/uinput/InputAbsInfo.aidl
@@ -0,0 +1,26 @@
+/*
+**
+** 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 src.com.android.commands.uinput;
+
+parcelable InputAbsInfo {
+ int value;
+ int minimum;
+ int maximum;
+ int fuzz;
+ int flat;
+ int resolution;
+}
diff --git a/cmds/uinput/src/com/android/commands/uinput/Uinput.java b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
new file mode 100644
index 000000000000..f7601a2f7c07
--- /dev/null
+++ b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
@@ -0,0 +1,140 @@
+/*
+ * 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.commands.uinput;
+
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Uinput class encapsulates execution of "uinput" command. It parses the provided input stream
+ * parameters as JSON file format, extract event entries and perform commands of event entries.
+ * Uinput device will be created when performing registration command and used to inject events.
+ */
+public class Uinput {
+ private static final String TAG = "UINPUT";
+
+ private final Event.Reader mReader;
+ private final SparseArray<Device> mDevices;
+
+ private static void usage() {
+ error("Usage: uinput [FILE]");
+ }
+
+ /**
+ * Commandline "uinput" binary main entry
+ */
+ public static void main(String[] args) {
+ if (args.length != 1) {
+ usage();
+ System.exit(1);
+ }
+
+ InputStream stream = null;
+ try {
+ if (args[0].equals("-")) {
+ stream = System.in;
+ } else {
+ File f = new File(args[0]);
+ stream = new FileInputStream(f);
+ }
+ (new Uinput(stream)).run();
+ } catch (Exception e) {
+ error("Uinput injection failed.", e);
+ System.exit(1);
+ } finally {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ private Uinput(InputStream in) {
+ mDevices = new SparseArray<Device>();
+ try {
+ mReader = new Event.Reader(new InputStreamReader(in, "UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void run() {
+ try {
+ Event e = null;
+ while ((e = mReader.getNextEvent()) != null) {
+ process(e);
+ }
+ } catch (IOException ex) {
+ error("Error reading in events.", ex);
+ }
+
+ for (int i = 0; i < mDevices.size(); i++) {
+ mDevices.valueAt(i).close();
+ }
+ }
+
+ private void process(Event e) {
+ final int index = mDevices.indexOfKey(e.getId());
+ if (index >= 0) {
+ Device d = mDevices.valueAt(index);
+ if (Event.COMMAND_DELAY.equals(e.getCommand())) {
+ d.addDelay(e.getDuration());
+ } else if (Event.COMMAND_INJECT.equals(e.getCommand())) {
+ d.injectEvent(e.getInjections());
+ } else {
+ if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
+ error("Device id=" + e.getId() + " is already registered. Ignoring event.");
+ } else {
+ error("Unknown command \"" + e.getCommand() + "\". Ignoring event.");
+ }
+ }
+ } else if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
+ registerDevice(e);
+ } else {
+ Log.e(TAG, "Unknown device id specified. Ignoring event.");
+ }
+ }
+
+ private void registerDevice(Event e) {
+ if (!Event.COMMAND_REGISTER.equals(e.getCommand())) {
+ throw new IllegalStateException(
+ "Tried to send command \"" + e.getCommand() + "\" to an unregistered device!");
+ }
+ int id = e.getId();
+ Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(), e.getBus(),
+ e.getConfiguration(), e.getFfEffectsMax(), e.getAbsInfo());
+ mDevices.append(id, d);
+ }
+
+ private static void error(String msg) {
+ error(msg, null);
+ }
+
+ private static void error(String msg, Exception e) {
+ Log.e(TAG, msg);
+ if (e != null) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ }
+ }
+}
diff --git a/cmds/uinput/uinput b/cmds/uinput/uinput
new file mode 100755
index 000000000000..ab2770ee2043
--- /dev/null
+++ b/cmds/uinput/uinput
@@ -0,0 +1,9 @@
+#!/system/bin/sh
+
+# Preload the native portion libuinputcommand_jni.so to bypass the dependency
+# checks in the Java classloader, which prohibit dependencies that aren't
+# listed in system/core/rootdir/etc/public.libraries.android.txt.
+export LD_PRELOAD=libuinputcommand_jni.so
+
+export CLASSPATH=/system/framework/uinput.jar
+exec app_process /system/bin com.android.commands.uinput.Uinput "$@"
diff --git a/config/Android.bp b/config/Android.bp
index 0fb56cb3410a..8dd409b51eee 100644
--- a/config/Android.bp
+++ b/config/Android.bp
@@ -13,6 +13,6 @@
// limitations under the License.
filegroup {
- name: "preloaded-classes-blacklist",
- srcs: ["preloaded-classes-blacklist"],
+ name: "preloaded-classes-denylist",
+ srcs: ["preloaded-classes-denylist"],
}
diff --git a/config/generate-preloaded-classes.sh b/config/generate-preloaded-classes.sh
index 0ad3a0263d95..b17a3660e1f1 100755
--- a/config/generate-preloaded-classes.sh
+++ b/config/generate-preloaded-classes.sh
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
if [ "$#" -lt 2 ]; then
- echo "Usage $0 <input classes file> <blacklist file> [extra classes files]"
+ echo "Usage $0 <input classes file> <denylist file> [extra classes files]"
exit 1
fi
@@ -31,9 +31,9 @@ echo "# Preloaded-classes filter file for phones.
#"
input=$1
-blacklist=$2
+denylist=$2
shift 2
extra_classes_files=("$@")
# Disable locale to enable lexicographical sorting
-LC_ALL=C sort "$input" "${extra_classes_files[@]}" | uniq | grep -f "$blacklist" -v -F -x | grep -v "\$NoPreloadHolder"
+LC_ALL=C sort "$input" "${extra_classes_files[@]}" | uniq | grep -f "$denylist" -v -F -x | grep -v "\$NoPreloadHolder"
diff --git a/config/preloaded-classes-blacklist b/config/preloaded-classes-denylist
index 8ab5273cd755..8ab5273cd755 100644
--- a/config/preloaded-classes-blacklist
+++ b/config/preloaded-classes-denylist
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d67b98620f37..caca05a9e3b3 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2242,9 +2242,9 @@ public final class ActivityThread extends ClientTransactionHandler {
* Resources if one has already been created.
*/
Resources getTopLevelResources(String resDir, String[] splitResDirs, String[] overlayDirs,
- String[] libDirs, int displayId, LoadedApk pkgInfo) {
+ String[] libDirs, LoadedApk pkgInfo) {
return mResourcesManager.getResources(null, resDir, splitResDirs, overlayDirs, libDirs,
- displayId, null, pkgInfo.getCompatibilityInfo(), pkgInfo.getClassLoader(), null);
+ null, null, pkgInfo.getCompatibilityInfo(), pkgInfo.getClassLoader(), null);
}
@UnsupportedAppUsage
@@ -5656,6 +5656,11 @@ public final class ActivityThread extends ClientTransactionHandler {
throw new IllegalArgumentException("Activity token not set. Is the activity attached?");
}
+ // WindowConfiguration differences aren't considered as public, check it separately.
+ // multi-window / pip mode changes, if any, should be sent before the configuration
+ // change callback, see also PinnedStackTests#testConfigurationChangeOrderDuringTransition
+ handleWindowingModeChangeIfNeeded(activity, newConfig);
+
final boolean movedToDifferentDisplay = isDifferentDisplay(activity, displayId);
boolean shouldReportChange = false;
if (activity.mCurrentConfig == null) {
@@ -5692,8 +5697,7 @@ public final class ActivityThread extends ClientTransactionHandler {
// many places.
final Configuration finalOverrideConfig = createNewConfigAndUpdateIfNotNull(
amOverrideConfig, contextThemeWrapperOverrideConfig);
- mResourcesManager.updateResourcesForActivity(activityToken, finalOverrideConfig,
- displayId, movedToDifferentDisplay);
+ mResourcesManager.updateResourcesForActivity(activityToken, finalOverrideConfig, displayId);
activity.mConfigChangeFlags = 0;
activity.mCurrentConfig = new Configuration(newConfig);
@@ -5709,11 +5713,6 @@ public final class ActivityThread extends ClientTransactionHandler {
}
if (shouldReportChange) {
- // multi-window / pip mode changes, if any, should be sent before the configuration
- // change callback, see also
- // PinnedStackTests#testConfigurationChangeOrderDuringTransition
- handleWindowingModeChangeIfNeeded(activity, newConfig);
-
activity.mCalled = false;
activity.onConfigurationChanged(configToReport);
if (!activity.mCalled) {
@@ -6014,6 +6013,11 @@ public final class ActivityThread extends ClientTransactionHandler {
r.mPendingOverrideConfig = null;
}
+ if (displayId == INVALID_DISPLAY) {
+ // If INVALID_DISPLAY is passed assume that the activity should keep its current
+ // display.
+ displayId = r.activity.getDisplayId();
+ }
final boolean movedToDifferentDisplay = isDifferentDisplay(r.activity, displayId);
if (r.overrideConfig != null && !r.overrideConfig.isOtherSeqNewer(overrideConfig)
&& !movedToDifferentDisplay) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 95136bb46339..00557114bab0 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1145,9 +1145,24 @@ public class AppOpsManager {
/** @hide */
public static final int OP_NO_ISOLATED_STORAGE = AppProtoEnums.APP_OP_NO_ISOLATED_STORAGE;
+ /**
+ * Phone call is using microphone
+ *
+ * @hide
+ */
+ // TODO: Add as AppProtoEnums
+ public static final int OP_PHONE_CALL_MICROPHONE = 100;
+ /**
+ * Phone call is using camera
+ *
+ * @hide
+ */
+ // TODO: Add as AppProtoEnums
+ public static final int OP_PHONE_CALL_CAMERA = 101;
+
/** @hide */
@UnsupportedAppUsage
- public static final int _NUM_OP = 100;
+ public static final int _NUM_OP = 102;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1469,6 +1484,19 @@ public class AppOpsManager {
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
+ /**
+ * Phone call is using microphone
+ *
+ * @hide
+ */
+ public static final String OPSTR_PHONE_CALL_MICROPHONE = "android:phone_call_microphone";
+ /**
+ * Phone call is using camera
+ *
+ * @hide
+ */
+ public static final String OPSTR_PHONE_CALL_CAMERA = "android:phone_call_camera";
+
/** {@link #sAppOpsToNote} not initialized yet for this op */
private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
/** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -1658,6 +1686,8 @@ public class AppOpsManager {
OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, //AUTO_REVOKE_PERMISSIONS_IF_UNUSED
OP_AUTO_REVOKE_MANAGED_BY_INSTALLER, //OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
OP_NO_ISOLATED_STORAGE, // NO_ISOLATED_STORAGE
+ OP_PHONE_CALL_MICROPHONE, // OP_PHONE_CALL_MICROPHONE
+ OP_PHONE_CALL_CAMERA, // OP_PHONE_CALL_CAMERA
};
/**
@@ -1764,6 +1794,8 @@ public class AppOpsManager {
OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
OPSTR_AUTO_REVOKE_MANAGED_BY_INSTALLER,
OPSTR_NO_ISOLATED_STORAGE,
+ OPSTR_PHONE_CALL_MICROPHONE,
+ OPSTR_PHONE_CALL_CAMERA,
};
/**
@@ -1871,6 +1903,8 @@ public class AppOpsManager {
"AUTO_REVOKE_PERMISSIONS_IF_UNUSED",
"AUTO_REVOKE_MANAGED_BY_INSTALLER",
"NO_ISOLATED_STORAGE",
+ "PHONE_CALL_MICROPHONE",
+ "PHONE_CALL_CAMERA",
};
/**
@@ -1979,6 +2013,8 @@ public class AppOpsManager {
null, // no permission for OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
null, // no permission for OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
null, // no permission for OP_NO_ISOLATED_STORAGE
+ null, // no permission for OP_PHONE_CALL_MICROPHONE
+ null, // no permission for OP_PHONE_CALL_CAMERA
};
/**
@@ -2087,6 +2123,8 @@ public class AppOpsManager {
null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
null, // AUTO_REVOKE_MANAGED_BY_INSTALLER
null, // NO_ISOLATED_STORAGE
+ null, // PHONE_CALL_MICROPHONE
+ null, // PHONE_CALL_MICROPHONE
};
/**
@@ -2194,6 +2232,8 @@ public class AppOpsManager {
null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
null, // AUTO_REVOKE_MANAGED_BY_INSTALLER
null, // NO_ISOLATED_STORAGE
+ null, // PHONE_CALL_MICROPHONE
+ null, // PHONE_CALL_CAMERA
};
/**
@@ -2300,6 +2340,8 @@ public class AppOpsManager {
AppOpsManager.MODE_DEFAULT, // OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
AppOpsManager.MODE_ALLOWED, // OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
AppOpsManager.MODE_ERRORED, // OP_NO_ISOLATED_STORAGE
+ AppOpsManager.MODE_ALLOWED, // PHONE_CALL_MICROPHONE
+ AppOpsManager.MODE_ALLOWED, // PHONE_CALL_CAMERA
};
/**
@@ -2410,6 +2452,8 @@ public class AppOpsManager {
false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
false, // AUTO_REVOKE_MANAGED_BY_INSTALLER
true, // NO_ISOLATED_STORAGE
+ false, // PHONE_CALL_MICROPHONE
+ false, // PHONE_CALL_CAMERA
};
/**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 676c6c01d349..340d5a12f92e 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -96,7 +96,6 @@ import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.LauncherIcons;
import android.util.Log;
-import android.view.Display;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.Immutable;
@@ -1748,7 +1747,7 @@ public class ApplicationPackageManager extends PackageManager {
final Resources r = mContext.mMainThread.getTopLevelResources(
sameUid ? app.sourceDir : app.publicSourceDir,
sameUid ? app.splitSourceDirs : app.splitPublicSourceDirs,
- app.resourceDirs, app.sharedLibraryFiles, Display.DEFAULT_DISPLAY,
+ app.resourceDirs, app.sharedLibraryFiles,
mContext.mPackageInfo);
if (r != null) {
return r;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f6b533434ac2..cee607fd7428 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -187,6 +187,16 @@ class ContextImpl extends Context {
private static final String XATTR_INODE_CODE_CACHE = "user.inode_code_cache";
/**
+ * Special intent extra that critical system apps can use to hide the notification for a
+ * foreground service. This extra should be placed in the intent passed into {@link
+ * #startForegroundService(Intent)}.
+ *
+ * @hide
+ */
+ private static final String EXTRA_HIDDEN_FOREGROUND_SERVICE =
+ "android.intent.extra.HIDDEN_FOREGROUND_SERVICE";
+
+ /**
* Map from package name, to preference name, to cached preferences.
*/
@GuardedBy("ContextImpl.class")
@@ -227,6 +237,15 @@ class ContextImpl extends Context {
private @NonNull Resources mResources;
private @Nullable Display mDisplay; // may be null if invalid display or not initialized yet.
+ /**
+ * If set to {@code true} the resources for this context will be configured for mDisplay which
+ * will override the display configuration inherited from {@link #mToken} (or the global
+ * configuration if mToken is null). Typically set for display contexts and contexts derived
+ * from display contexts where changes to the activity display and the global configuration
+ * display should not impact their resources.
+ */
+ private boolean mForceDisplayOverrideInResources;
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final int mFlags;
@@ -1698,9 +1717,12 @@ class ContextImpl extends Context {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
+ final boolean hideForegroundNotification = requireForeground
+ && service.getBooleanExtra(EXTRA_HIDDEN_FOREGROUND_SERVICE, false);
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
+ hideForegroundNotification,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
@@ -2246,8 +2268,8 @@ class ContextImpl extends Context {
}
private static Resources createResources(IBinder activityToken, LoadedApk pi, String splitName,
- int displayId, Configuration overrideConfig, CompatibilityInfo compatInfo,
- List<ResourcesLoader> resourcesLoader) {
+ @Nullable Integer overrideDisplayId, Configuration overrideConfig,
+ CompatibilityInfo compatInfo, List<ResourcesLoader> resourcesLoader) {
final String[] splitResDirs;
final ClassLoader classLoader;
try {
@@ -2261,7 +2283,7 @@ class ContextImpl extends Context {
splitResDirs,
pi.getOverlayDirs(),
pi.getApplicationInfo().sharedLibraryFiles,
- displayId,
+ overrideDisplayId,
overrideConfig,
compatInfo,
classLoader,
@@ -2278,8 +2300,10 @@ class ContextImpl extends Context {
new UserHandle(UserHandle.getUserId(application.uid)), flags, null, null);
final int displayId = getDisplayId();
+ final Integer overrideDisplayId = mForceDisplayOverrideInResources
+ ? displayId : null;
- c.setResources(createResources(mToken, pi, null, displayId, null,
+ c.setResources(createResources(mToken, pi, null, overrideDisplayId, null,
getDisplayAdjustments(displayId).getCompatibilityInfo(), null));
if (c.mResources != null) {
return c;
@@ -2313,8 +2337,10 @@ class ContextImpl extends Context {
mToken, user, flags, null, null);
final int displayId = getDisplayId();
+ final Integer overrideDisplayId = mForceDisplayOverrideInResources
+ ? displayId : null;
- c.setResources(createResources(mToken, pi, null, displayId, null,
+ c.setResources(createResources(mToken, pi, null, overrideDisplayId, null,
getDisplayAdjustments(displayId).getCompatibilityInfo(), null));
if (c.mResources != null) {
return c;
@@ -2348,15 +2374,13 @@ class ContextImpl extends Context {
final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo,
mAttributionTag, splitName, mToken, mUser, mFlags, classLoader, null);
- final int displayId = getDisplayId();
-
context.setResources(ResourcesManager.getInstance().getResources(
mToken,
mPackageInfo.getResDir(),
paths,
mPackageInfo.getOverlayDirs(),
mPackageInfo.getApplicationInfo().sharedLibraryFiles,
- displayId,
+ mForceDisplayOverrideInResources ? getDisplayId() : null,
null,
mPackageInfo.getCompatibilityInfo(),
classLoader,
@@ -2370,12 +2394,23 @@ class ContextImpl extends Context {
throw new IllegalArgumentException("overrideConfiguration must not be null");
}
+ if (mForceDisplayOverrideInResources) {
+ // Ensure the resources display metrics are adjusted to match the display this context
+ // is based on.
+ Configuration displayAdjustedConfig = new Configuration();
+ displayAdjustedConfig.setTo(mDisplay.getDisplayAdjustments().getConfiguration(),
+ ActivityInfo.CONFIG_WINDOW_CONFIGURATION, 1);
+ displayAdjustedConfig.updateFrom(overrideConfiguration);
+ overrideConfiguration = displayAdjustedConfig;
+ }
+
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
mSplitName, mToken, mUser, mFlags, mClassLoader, null);
final int displayId = getDisplayId();
-
- context.setResources(createResources(mToken, mPackageInfo, mSplitName, displayId,
+ final Integer overrideDisplayId = mForceDisplayOverrideInResources
+ ? displayId : null;
+ context.setResources(createResources(mToken, mPackageInfo, mSplitName, overrideDisplayId,
overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo(),
mResources.getLoaders()));
context.mIsUiContext = isUiContext() || isOuterUiContext();
@@ -2393,11 +2428,20 @@ class ContextImpl extends Context {
final int displayId = display.getDisplayId();
+ // Ensure the resources display metrics are adjusted to match the provided display.
+ Configuration overrideConfig = new Configuration();
+ overrideConfig.setTo(display.getDisplayAdjustments().getConfiguration(),
+ ActivityInfo.CONFIG_WINDOW_CONFIGURATION, 1);
+
context.setResources(createResources(mToken, mPackageInfo, mSplitName, displayId,
- null, getDisplayAdjustments(displayId).getCompatibilityInfo(),
+ overrideConfig, display.getDisplayAdjustments().getCompatibilityInfo(),
mResources.getLoaders()));
context.mDisplay = display;
context.mIsAssociatedWithDisplay = true;
+ // Display contexts and any context derived from a display context should always override
+ // the display that would otherwise be inherited from mToken (or the global configuration if
+ // mToken is null).
+ context.mForceDisplayOverrideInResources = true;
return context;
}
@@ -2415,8 +2459,10 @@ class ContextImpl extends Context {
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
mSplitName, token, mUser, mFlags, mClassLoader, null);
context.mIsUiContext = true;
-
context.mIsAssociatedWithDisplay = true;
+ // Window contexts receive configurations directly from the server and as such do not
+ // need to override their display in ResourcesManager.
+ context.mForceDisplayOverrideInResources = false;
return context;
}
@@ -2759,6 +2805,7 @@ class ContextImpl extends Context {
mDisplay = container.mDisplay;
mIsAssociatedWithDisplay = container.mIsAssociatedWithDisplay;
mIsSystemOrSystemUiContext = container.mIsSystemOrSystemUiContext;
+ mForceDisplayOverrideInResources = container.mForceDisplayOverrideInResources;
} else {
mBasePackageName = packageInfo.mPackageName;
ApplicationInfo ainfo = packageInfo.getApplicationInfo();
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index f37ca61ba69f..0a47248e3b70 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -156,7 +156,8 @@ interface IActivityManager {
boolean refContentProvider(in IBinder connection, int stableDelta, int unstableDelta);
PendingIntent getRunningServiceControlPanel(in ComponentName service);
ComponentName startService(in IApplicationThread caller, in Intent service,
- in String resolvedType, boolean requireForeground, in String callingPackage,
+ in String resolvedType, boolean requireForeground,
+ boolean hideForegroundNotification, in String callingPackage,
in String callingFeatureId, int userId);
@UnsupportedAppUsage
int stopService(in IApplicationThread caller, in Intent service,
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index aa6a08b6d2e4..202b6152d2ea 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -56,7 +56,6 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
-import android.view.Display;
import android.view.DisplayAdjustments;
import com.android.internal.util.ArrayUtils;
@@ -367,7 +366,7 @@ public final class LoadedApk {
mResources = ResourcesManager.getInstance().getResources(null, mResDir,
splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
- Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
+ null, null, getCompatibilityInfo(),
getClassLoader(), mApplication == null ? null
: mApplication.getResources().getLoaders());
}
@@ -1231,7 +1230,7 @@ public final class LoadedApk {
mResources = ResourcesManager.getInstance().getResources(null, mResDir,
splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
- Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
+ null, null, getCompatibilityInfo(),
getClassLoader(), null);
}
return mResources;
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index fb2120e5a35b..7cd3fcad177b 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -17,6 +17,8 @@
package android.app;
import static android.app.ActivityThread.DEBUG_CONFIGURATION;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -61,6 +63,7 @@ import java.util.List;
import java.util.Objects;
import java.util.WeakHashMap;
import java.util.function.Consumer;
+import java.util.function.Function;
/** @hide */
public class ResourcesManager {
@@ -82,6 +85,12 @@ public class ResourcesManager {
private final Configuration mResConfiguration = new Configuration();
/**
+ * The display upon which all Resources are based. Activity, window token, and display context
+ * resources apply their overrides to this display id.
+ */
+ private int mResDisplayId = DEFAULT_DISPLAY;
+
+ /**
* A mapping of ResourceImpls and their configurations. These are heavy weight objects
* which should be reused as much as possible.
*/
@@ -155,20 +164,79 @@ public class ResourcesManager {
private final ArrayMap<ApkKey, WeakReference<ApkAssets>> mCachedApkAssets = new ArrayMap<>();
/**
- * Resources and base configuration override associated with an Activity.
+ * Class containing the base configuration override and set of resources associated with an
+ * Activity or {@link WindowContext}.
*/
private static class ActivityResources {
+ /**
+ * Override config to apply to all resources associated with the token this instance is
+ * based on.
+ *
+ * @see #activityResources
+ * @see #getResources(IBinder, String, String[], String[], String[], Integer, Configuration,
+ * CompatibilityInfo, ClassLoader, List)
+ */
+ public final Configuration overrideConfig = new Configuration();
+
+ /**
+ * The display to apply to all resources associated with the token this instance is based
+ * on.
+ */
+ public int overrideDisplayId;
+
+ /** List of {@link ActivityResource} associated with the token this instance is based on. */
+ public final ArrayList<ActivityResource> activityResources = new ArrayList<>();
+
+ public final ReferenceQueue<Resources> activityResourcesQueue = new ReferenceQueue<>();
+
@UnsupportedAppUsage
- private ActivityResources() {
+ private ActivityResources() {}
+
+ /** Returns the number of live resource references within {@code activityResources}. */
+ public int countLiveReferences() {
+ int count = 0;
+ for (int i = 0; i < activityResources.size(); i++) {
+ WeakReference<Resources> resources = activityResources.get(i).resources;
+ if (resources != null && resources.get() != null) {
+ count++;
+ }
+ }
+ return count;
}
+ }
+
+ /**
+ * Contains a resource derived from an {@link Activity} or {@link WindowContext} and information
+ * about how this resource expects its configuration to differ from the token's.
+ *
+ * @see ActivityResources
+ */
+ // TODO: Ideally this class should be called something token related, like TokenBasedResource.
+ private static class ActivityResource {
+ /**
+ * The override configuration applied on top of the token's override config for this
+ * resource.
+ */
public final Configuration overrideConfig = new Configuration();
- public final ArrayList<WeakReference<Resources>> activityResources = new ArrayList<>();
- final ReferenceQueue<Resources> activityResourcesQueue = new ReferenceQueue<>();
+
+ /**
+ * If non-null this resource expects its configuration to override the display from the
+ * token's configuration.
+ *
+ * @see #applyDisplayMetricsToConfiguration(DisplayMetrics, Configuration)
+ */
+ @Nullable
+ public Integer overrideDisplayId;
+
+ @Nullable
+ public WeakReference<Resources> resources;
+
+ private ActivityResource() {}
}
/**
- * Each Activity may has a base override configuration that is applied to each Resources object,
- * which in turn may have their own override configuration specified.
+ * Each Activity or WindowToken may has a base override configuration that is applied to each
+ * Resources object, which in turn may have their own override configuration specified.
*/
@UnsupportedAppUsage
private final WeakHashMap<IBinder, ActivityResources> mActivityResourceReferences =
@@ -241,8 +309,7 @@ public class ResourcesManager {
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public DisplayMetrics getDisplayMetrics() {
- return getDisplayMetrics(Display.DEFAULT_DISPLAY,
- DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
+ return getDisplayMetrics(mResDisplayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
}
/**
@@ -260,8 +327,8 @@ public class ResourcesManager {
return dm;
}
- private static void applyNonDefaultDisplayMetricsToConfiguration(
- @NonNull DisplayMetrics dm, @NonNull Configuration config) {
+ private static void applyDisplayMetricsToConfiguration(@NonNull DisplayMetrics dm,
+ @NonNull Configuration config) {
config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
config.densityDpi = dm.densityDpi;
config.screenWidthDp = (int) (dm.widthPixels / dm.density);
@@ -502,7 +569,7 @@ public class ResourcesManager {
int references = countLiveReferences(mResourceReferences);
for (ActivityResources activityResources : mActivityResourceReferences.values()) {
- references += countLiveReferences(activityResources.activityResources);
+ references += activityResources.countLiveReferences();
}
pw.println(references);
@@ -511,38 +578,36 @@ public class ResourcesManager {
}
}
- private Configuration generateConfig(@NonNull ResourcesKey key, @NonNull DisplayMetrics dm) {
+ private Configuration generateConfig(@NonNull ResourcesKey key) {
Configuration config;
- final boolean isDefaultDisplay = (key.mDisplayId == Display.DEFAULT_DISPLAY);
final boolean hasOverrideConfig = key.hasOverrideConfiguration();
- if (!isDefaultDisplay || hasOverrideConfig) {
+ if (hasOverrideConfig) {
config = new Configuration(getConfiguration());
- if (!isDefaultDisplay) {
- applyNonDefaultDisplayMetricsToConfiguration(dm, config);
- }
- if (hasOverrideConfig) {
- config.updateFrom(key.mOverrideConfiguration);
- if (DEBUG) Slog.v(TAG, "Applied overrideConfig=" + key.mOverrideConfiguration);
- }
+ config.updateFrom(key.mOverrideConfiguration);
+ if (DEBUG) Slog.v(TAG, "Applied overrideConfig=" + key.mOverrideConfiguration);
} else {
config = getConfiguration();
}
return config;
}
+ private int generateDisplayId(@NonNull ResourcesKey key) {
+ return key.mDisplayId != INVALID_DISPLAY ? key.mDisplayId : mResDisplayId;
+ }
+
private @Nullable ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key,
@Nullable ApkAssetsSupplier apkSupplier) {
- final DisplayAdjustments daj = new DisplayAdjustments(key.mOverrideConfiguration);
- daj.setCompatibilityInfo(key.mCompatInfo);
-
final AssetManager assets = createAssetManager(key, apkSupplier);
if (assets == null) {
return null;
}
- final DisplayMetrics dm = getDisplayMetrics(key.mDisplayId, daj);
- final Configuration config = generateConfig(key, dm);
- final ResourcesImpl impl = new ResourcesImpl(assets, dm, config, daj);
+ final DisplayAdjustments daj = new DisplayAdjustments(key.mOverrideConfiguration);
+ daj.setCompatibilityInfo(key.mCompatInfo);
+
+ final Configuration config = generateConfig(key);
+ final DisplayMetrics displayMetrics = getDisplayMetrics(generateDisplayId(key), daj);
+ final ResourcesImpl impl = new ResourcesImpl(assets, displayMetrics, config, daj);
if (DEBUG) {
Slog.d(TAG, "- creating impl=" + impl + " with key: " + key);
@@ -652,8 +717,8 @@ public class ResourcesManager {
final int size = activityResources.activityResources.size();
for (int index = 0; index < size; index++) {
- WeakReference<Resources> ref = activityResources.activityResources.get(index);
- Resources resources = ref.get();
+ ActivityResource activityResource = activityResources.activityResources.get(index);
+ Resources resources = activityResource.resources.get();
ResourcesKey key = resources == null ? null : findKeyForResourceImplLocked(
resources.getImpl());
@@ -667,20 +732,28 @@ public class ResourcesManager {
return null;
}
- private @NonNull Resources createResourcesForActivityLocked(@NonNull IBinder activityToken,
+ @NonNull
+ private Resources createResourcesForActivityLocked(@NonNull IBinder activityToken,
+ @NonNull Configuration initialOverrideConfig, @Nullable Integer overrideDisplayId,
@NonNull ClassLoader classLoader, @NonNull ResourcesImpl impl,
@NonNull CompatibilityInfo compatInfo) {
final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
activityToken);
cleanupReferences(activityResources.activityResources,
- activityResources.activityResourcesQueue);
+ activityResources.activityResourcesQueue,
+ (r) -> r.resources);
Resources resources = compatInfo.needsCompatResources() ? new CompatResources(classLoader)
: new Resources(classLoader);
resources.setImpl(impl);
resources.setCallbacks(mUpdateCallbacks);
- activityResources.activityResources.add(
- new WeakReference<>(resources, activityResources.activityResourcesQueue));
+
+ ActivityResource activityResource = new ActivityResource();
+ activityResource.resources = new WeakReference<>(resources,
+ activityResources.activityResourcesQueue);
+ activityResource.overrideConfig.setTo(initialOverrideConfig);
+ activityResource.overrideDisplayId = overrideDisplayId;
+ activityResources.activityResources.add(activityResource);
if (DEBUG) {
Slog.d(TAG, "- creating new ref=" + resources);
Slog.d(TAG, "- setting ref=" + resources + " with impl=" + impl);
@@ -706,7 +779,7 @@ public class ResourcesManager {
/**
* Creates base resources for a binder token. Calls to
- * {@link #getResources(IBinder, String, String[], String[], String[], int, Configuration,
+ * {@link #getResources(IBinder, String, String[], String[], String[], Integer, Configuration,
* CompatibilityInfo, ClassLoader, List)} with the same binder token will have their override
* configurations merged with the one specified here.
*
@@ -743,7 +816,7 @@ public class ResourcesManager {
overlayDirs,
libDirs,
displayId,
- overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+ overrideConfig,
compatInfo,
loaders == null ? null : loaders.toArray(new ResourcesLoader[0]));
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
@@ -759,10 +832,7 @@ public class ResourcesManager {
}
// Update any existing Activity Resources references.
- updateResourcesForActivity(token, overrideConfig, displayId,
- false /* movedToDifferentDisplay */);
-
- rebaseKeyForActivity(token, key);
+ updateResourcesForActivity(token, overrideConfig, displayId);
synchronized (this) {
Resources resources = findResourcesForActivityLocked(token, key,
@@ -773,7 +843,9 @@ public class ResourcesManager {
}
// Now request an actual Resources object.
- return createResources(token, key, classLoader, /* apkSupplier */ null);
+ return createResourcesForActivity(token, key,
+ /* initialOverrideConfig */ Configuration.EMPTY, /* overrideDisplayId */ null,
+ classLoader, /* apkSupplier */ null);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
@@ -781,20 +853,65 @@ public class ResourcesManager {
/**
* Rebases a key's override config on top of the Activity's base override.
+ *
+ * @param activityToken the token the supplied {@code key} is derived from.
+ * @param key the key to rebase
+ * @param overridesActivityDisplay whether this key is overriding the display from the token
*/
- private void rebaseKeyForActivity(IBinder activityToken, ResourcesKey key) {
+ private void rebaseKeyForActivity(IBinder activityToken, ResourcesKey key,
+ boolean overridesActivityDisplay) {
synchronized (this) {
final ActivityResources activityResources =
getOrCreateActivityResourcesStructLocked(activityToken);
- // Rebase the key's override config on top of the Activity's base override.
- if (key.hasOverrideConfiguration()
- && !activityResources.overrideConfig.equals(Configuration.EMPTY)) {
- final Configuration temp = new Configuration(activityResources.overrideConfig);
- temp.updateFrom(key.mOverrideConfiguration);
- key.mOverrideConfiguration.setTo(temp);
+ if (key.mDisplayId == INVALID_DISPLAY) {
+ key.mDisplayId = activityResources.overrideDisplayId;
+ }
+
+ Configuration config;
+ if (key.hasOverrideConfiguration()) {
+ config = new Configuration(activityResources.overrideConfig);
+ config.updateFrom(key.mOverrideConfiguration);
+ } else {
+ config = activityResources.overrideConfig;
+ }
+
+ if (overridesActivityDisplay
+ && key.mOverrideConfiguration.windowConfiguration.getAppBounds() == null) {
+ if (!key.hasOverrideConfiguration()) {
+ // Make a copy to handle the case where the override config is set to defaults.
+ config = new Configuration(config);
+ }
+
+ // If this key is overriding the display from the token and the key's
+ // window config app bounds is null we need to explicitly override this to
+ // ensure the display adjustments are as expected.
+ config.windowConfiguration.setAppBounds(null);
}
+
+ key.mOverrideConfiguration.setTo(config);
+ }
+ }
+
+ /**
+ * Rebases a key's override config with display metrics of the {@code overrideDisplay} paired
+ * with the {code displayAdjustments}.
+ *
+ * @see #applyDisplayMetricsToConfiguration(DisplayMetrics, Configuration)
+ */
+ private void rebaseKeyForDisplay(ResourcesKey key, int overrideDisplay) {
+ final Configuration temp = new Configuration();
+
+ DisplayAdjustments daj = new DisplayAdjustments(key.mOverrideConfiguration);
+ daj.setCompatibilityInfo(key.mCompatInfo);
+
+ final DisplayMetrics dm = getDisplayMetrics(overrideDisplay, daj);
+ applyDisplayMetricsToConfiguration(dm, temp);
+
+ if (key.hasOverrideConfiguration()) {
+ temp.updateFrom(key.mOverrideConfiguration);
}
+ key.mOverrideConfiguration.setTo(temp);
}
/**
@@ -802,18 +919,28 @@ public class ResourcesManager {
*/
private static <T> void cleanupReferences(ArrayList<WeakReference<T>> references,
ReferenceQueue<T> referenceQueue) {
- Reference<? extends T> enduedRef = referenceQueue.poll();
- if (enduedRef == null) {
+ cleanupReferences(references, referenceQueue, Function.identity());
+ }
+
+ /**
+ * Check WeakReferences and remove any dead references so they don't pile up.
+ */
+ private static <C, T> void cleanupReferences(ArrayList<C> referenceContainers,
+ ReferenceQueue<T> referenceQueue, Function<C, WeakReference<T>> unwrappingFunction) {
+ Reference<? extends T> enqueuedRef = referenceQueue.poll();
+ if (enqueuedRef == null) {
return;
}
final HashSet<Reference<? extends T>> deadReferences = new HashSet<>();
- for (; enduedRef != null; enduedRef = referenceQueue.poll()) {
- deadReferences.add(enduedRef);
+ for (; enqueuedRef != null; enqueuedRef = referenceQueue.poll()) {
+ deadReferences.add(enqueuedRef);
}
- ArrayUtils.unstableRemoveIf(references,
- (ref) -> ref == null || deadReferences.contains(ref));
+ ArrayUtils.unstableRemoveIf(referenceContainers, (refContainer) -> {
+ WeakReference<T> ref = unwrappingFunction.apply(refContainer);
+ return ref == null || deadReferences.contains(ref);
+ });
}
/**
@@ -825,8 +952,8 @@ public class ResourcesManager {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
"ResourcesManager#createApkAssetsSupplierNotLocked");
try {
- if (Thread.holdsLock(this)) {
- Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
+ if (DEBUG && Thread.holdsLock(this)) {
+ Slog.w(TAG, "Calling thread " + Thread.currentThread().getName()
+ " is holding mLock", new Throwable());
}
@@ -849,23 +976,21 @@ public class ResourcesManager {
/**
* Creates a Resources object set with a ResourcesImpl object matching the given key.
*
- * @param activityToken The Activity this Resources object should be associated with.
* @param key The key describing the parameters of the ResourcesImpl object.
* @param classLoader The classloader to use for the Resources object.
* If null, {@link ClassLoader#getSystemClassLoader()} is used.
- * @param apkSupplier The apk assets supplier to use when creating a new ResourcesImpl object.
* @return A Resources object that gets updated when
* {@link #applyConfigurationToResourcesLocked(Configuration, CompatibilityInfo)}
* is called.
*/
- private @Nullable Resources createResources(@Nullable IBinder activityToken,
- @NonNull ResourcesKey key, @NonNull ClassLoader classLoader,
+ @Nullable
+ private Resources createResources(@NonNull ResourcesKey key, @NonNull ClassLoader classLoader,
@Nullable ApkAssetsSupplier apkSupplier) {
synchronized (this) {
if (DEBUG) {
Throwable here = new Throwable();
here.fillInStackTrace();
- Slog.w(TAG, "!! Get resources for activity=" + activityToken + " key=" + key, here);
+ Slog.w(TAG, "!! Create resources for key=" + key, here);
}
ResourcesImpl resourcesImpl = findOrCreateResourcesImplForKeyLocked(key, apkSupplier);
@@ -873,12 +998,29 @@ public class ResourcesManager {
return null;
}
- if (activityToken != null) {
- return createResourcesForActivityLocked(activityToken, classLoader,
- resourcesImpl, key.mCompatInfo);
- } else {
- return createResourcesLocked(classLoader, resourcesImpl, key.mCompatInfo);
+ return createResourcesLocked(classLoader, resourcesImpl, key.mCompatInfo);
+ }
+ }
+
+ @Nullable
+ private Resources createResourcesForActivity(@NonNull IBinder activityToken,
+ @NonNull ResourcesKey key, @NonNull Configuration initialOverrideConfig,
+ @Nullable Integer overrideDisplayId, @NonNull ClassLoader classLoader,
+ @Nullable ApkAssetsSupplier apkSupplier) {
+ synchronized (this) {
+ if (DEBUG) {
+ Throwable here = new Throwable();
+ here.fillInStackTrace();
+ Slog.w(TAG, "!! Get resources for activity=" + activityToken + " key=" + key, here);
+ }
+
+ ResourcesImpl resourcesImpl = findOrCreateResourcesImplForKeyLocked(key, apkSupplier);
+ if (resourcesImpl == null) {
+ return null;
}
+
+ return createResourcesForActivityLocked(activityToken, initialOverrideConfig,
+ overrideDisplayId, classLoader, resourcesImpl, key.mCompatInfo);
}
}
@@ -899,7 +1041,10 @@ public class ResourcesManager {
* @param splitResDirs An array of split resource paths. Can be null.
* @param overlayDirs An array of overlay paths. Can be null.
* @param libDirs An array of resource library paths. Can be null.
- * @param displayId The ID of the display for which to create the resources.
+ * @param overrideDisplayId The ID of the display for which the returned Resources should be
+ * based. This will cause display-based configuration properties to override those of the base
+ * Resources for the {@code activityToken}, or the global configuration if {@code activityToken}
+ * is null.
* @param overrideConfig The configuration to apply on top of the base configuration. Can be
* null. Mostly used with Activities that are in multi-window which may override width and
* height properties from the base config.
@@ -909,13 +1054,14 @@ public class ResourcesManager {
* {@link ClassLoader#getSystemClassLoader()} is used.
* @return a Resources object from which to access resources.
*/
- public @Nullable Resources getResources(
+ @Nullable
+ public Resources getResources(
@Nullable IBinder activityToken,
@Nullable String resDir,
@Nullable String[] splitResDirs,
@Nullable String[] overlayDirs,
@Nullable String[] libDirs,
- int displayId,
+ @Nullable Integer overrideDisplayId,
@Nullable Configuration overrideConfig,
@NonNull CompatibilityInfo compatInfo,
@Nullable ClassLoader classLoader,
@@ -927,20 +1073,30 @@ public class ResourcesManager {
splitResDirs,
overlayDirs,
libDirs,
- displayId,
- overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+ overrideDisplayId != null ? overrideDisplayId : INVALID_DISPLAY,
+ overrideConfig,
compatInfo,
loaders == null ? null : loaders.toArray(new ResourcesLoader[0]));
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
- if (activityToken != null) {
- rebaseKeyForActivity(activityToken, key);
- }
-
// Preload the ApkAssets required by the key to prevent performing heavy I/O while the
// ResourcesManager lock is held.
final ApkAssetsSupplier assetsSupplier = createApkAssetsSupplierNotLocked(key);
- return createResources(activityToken, key, classLoader, assetsSupplier);
+
+ if (overrideDisplayId != null) {
+ rebaseKeyForDisplay(key, overrideDisplayId);
+ }
+
+ Resources resources;
+ if (activityToken != null) {
+ Configuration initialOverrideConfig = new Configuration(key.mOverrideConfiguration);
+ rebaseKeyForActivity(activityToken, key, overrideDisplayId != null);
+ resources = createResourcesForActivity(activityToken, key, initialOverrideConfig,
+ overrideDisplayId, classLoader, assetsSupplier);
+ } else {
+ resources = createResources(key, classLoader, assetsSupplier);
+ }
+ return resources;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
@@ -949,24 +1105,26 @@ public class ResourcesManager {
/**
* Updates an Activity's Resources object with overrideConfig. The Resources object
* that was previously returned by {@link #getResources(IBinder, String, String[], String[],
- * String[], int, Configuration, CompatibilityInfo, ClassLoader, List)} is still valid and will
- * have the updated configuration.
+ * String[], Integer, Configuration, CompatibilityInfo, ClassLoader, List)} is still valid and
+ * will have the updated configuration.
*
* @param activityToken The Activity token.
* @param overrideConfig The configuration override to update.
* @param displayId Id of the display where activity currently resides.
- * @param movedToDifferentDisplay Indicates if the activity was moved to different display.
*/
public void updateResourcesForActivity(@NonNull IBinder activityToken,
- @Nullable Configuration overrideConfig, int displayId,
- boolean movedToDifferentDisplay) {
+ @Nullable Configuration overrideConfig, int displayId) {
try {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
"ResourcesManager#updateResourcesForActivity");
+ if (displayId == INVALID_DISPLAY) {
+ throw new IllegalArgumentException("displayId can not be INVALID_DISPLAY");
+ }
synchronized (this) {
final ActivityResources activityResources =
getOrCreateActivityResourcesStructLocked(activityToken);
+ boolean movedToDifferentDisplay = activityResources.overrideDisplayId != displayId;
if (Objects.equals(activityResources.overrideConfig, overrideConfig)
&& !movedToDifferentDisplay) {
// They are the same and no change of display id, no work to do.
@@ -983,6 +1141,8 @@ public class ResourcesManager {
} else {
activityResources.overrideConfig.unset();
}
+ // Update the Activity's override display id.
+ activityResources.overrideDisplayId = displayId;
if (DEBUG) {
Throwable here = new Throwable();
@@ -1000,24 +1160,26 @@ public class ResourcesManager {
// Rebase each Resources associated with this Activity.
final int refCount = activityResources.activityResources.size();
for (int i = 0; i < refCount; i++) {
- final WeakReference<Resources> weakResRef =
+ final ActivityResource activityResource =
activityResources.activityResources.get(i);
- final Resources resources = weakResRef.get();
+ final Resources resources = activityResource.resources.get();
if (resources == null) {
continue;
}
- final ResourcesKey newKey = rebaseActivityOverrideConfig(resources, oldConfig,
+ final ResourcesKey newKey = rebaseActivityOverrideConfig(activityResource,
overrideConfig, displayId);
- if (newKey != null) {
- final ResourcesImpl resourcesImpl =
- findOrCreateResourcesImplForKeyLocked(newKey);
- if (resourcesImpl != null && resourcesImpl != resources.getImpl()) {
- // Set the ResourcesImpl, updating it for all users of this Resources
- // object.
- resources.setImpl(resourcesImpl);
- }
+ if (newKey == null) {
+ continue;
+ }
+
+ final ResourcesImpl resourcesImpl =
+ findOrCreateResourcesImplForKeyLocked(newKey);
+ if (resourcesImpl != null && resourcesImpl != resources.getImpl()) {
+ // Set the ResourcesImpl, updating it for all users of this Resources
+ // object.
+ resources.setImpl(resourcesImpl);
}
}
}
@@ -1031,9 +1193,13 @@ public class ResourcesManager {
* that an Activity's Resources should be set to.
*/
@Nullable
- private ResourcesKey rebaseActivityOverrideConfig(@NonNull Resources resources,
- @NonNull Configuration oldOverrideConfig, @Nullable Configuration newOverrideConfig,
- int displayId) {
+ private ResourcesKey rebaseActivityOverrideConfig(@NonNull ActivityResource activityResource,
+ @Nullable Configuration newOverrideConfig, int displayId) {
+ final Resources resources = activityResource.resources.get();
+ if (resources == null) {
+ return null;
+ }
+
// Extract the ResourcesKey that was last used to create the Resources for this
// activity.
final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
@@ -1049,16 +1215,33 @@ public class ResourcesManager {
rebasedOverrideConfig.setTo(newOverrideConfig);
}
- final boolean hadOverrideConfig = !oldOverrideConfig.equals(Configuration.EMPTY);
- if (hadOverrideConfig && oldKey.hasOverrideConfiguration()) {
- // Generate a delta between the old base Activity override configuration and
- // the actual final override configuration that was used to figure out the
- // real delta this Resources object wanted.
- Configuration overrideOverrideConfig = Configuration.generateDelta(
- oldOverrideConfig, oldKey.mOverrideConfiguration);
- rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
+ final Integer overrideDisplayId = activityResource.overrideDisplayId;
+ if (overrideDisplayId != null) {
+ DisplayAdjustments displayAdjustments = new DisplayAdjustments(rebasedOverrideConfig);
+ displayAdjustments.getConfiguration().setTo(activityResource.overrideConfig);
+ displayAdjustments.setCompatibilityInfo(oldKey.mCompatInfo);
+
+ DisplayMetrics dm = getDisplayMetrics(overrideDisplayId, displayAdjustments);
+ applyDisplayMetricsToConfiguration(dm, rebasedOverrideConfig);
+ }
+
+ final boolean hasOverrideConfig =
+ !activityResource.overrideConfig.equals(Configuration.EMPTY);
+ if (hasOverrideConfig) {
+ rebasedOverrideConfig.updateFrom(activityResource.overrideConfig);
}
+ if (activityResource.overrideDisplayId != null
+ && activityResource.overrideConfig.windowConfiguration.getAppBounds() == null) {
+ // If this activity resource is overriding the display from the token and the key's
+ // window config app bounds is null we need to explicitly override this to
+ // ensure the display adjustments are as expected.
+ rebasedOverrideConfig.windowConfiguration.setAppBounds(null);
+ }
+
+ // Ensure the new key keeps the expected override display instead of the new token display.
+ displayId = overrideDisplayId != null ? overrideDisplayId : displayId;
+
// Create the new ResourcesKey with the rebased override config.
final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir,
oldKey.mSplitResDirs, oldKey.mOverlayDirs, oldKey.mLibDirs,
@@ -1090,12 +1273,11 @@ public class ResourcesManager {
+ mResConfiguration.seq + ", newSeq=" + config.seq);
return false;
}
- int changes = mResConfiguration.updateFrom(config);
+
// Things might have changed in display manager, so clear the cached displays.
mAdjustedDisplays.clear();
- DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
-
+ int changes = mResConfiguration.updateFrom(config);
if (compat != null && (mResCompatibilityInfo == null ||
!mResCompatibilityInfo.equals(compat))) {
mResCompatibilityInfo = compat;
@@ -1104,10 +1286,10 @@ public class ResourcesManager {
| ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
}
- Resources.updateSystemConfiguration(config, defaultDisplayMetrics, compat);
+ DisplayMetrics displayMetrics = getDisplayMetrics();
+ Resources.updateSystemConfiguration(config, displayMetrics, compat);
ApplicationPackageManager.configurationChanged();
- //Slog.i(TAG, "Configuration changed in " + currentPackageName());
Configuration tmpConfig = new Configuration();
@@ -1137,11 +1319,7 @@ public class ResourcesManager {
}
tmpConfig.setTo(config);
-
- // Apply the override configuration before setting the display adjustments to ensure that
- // the process config does not override activity display adjustments.
- final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
- if (hasOverrideConfiguration) {
+ if (key.hasOverrideConfiguration()) {
tmpConfig.updateFrom(key.mOverrideConfiguration);
}
@@ -1153,22 +1331,8 @@ public class ResourcesManager {
daj = new DisplayAdjustments(daj);
daj.setCompatibilityInfo(compat);
}
-
- final int displayId = key.mDisplayId;
- if (displayId == Display.DEFAULT_DISPLAY) {
- daj.setConfiguration(tmpConfig);
- }
- DisplayMetrics dm = getDisplayMetrics(displayId, daj);
- if (displayId != Display.DEFAULT_DISPLAY) {
- applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
-
- // Re-apply the override configuration to ensure that configuration contexts based on
- // a display context (ex: createDisplayContext().createConfigurationContext()) have the
- // correct override.
- if (hasOverrideConfiguration) {
- tmpConfig.updateFrom(key.mOverrideConfiguration);
- }
- }
+ daj.setConfiguration(tmpConfig);
+ DisplayMetrics dm = getDisplayMetrics(generateDisplayId(key), daj);
resourcesImpl.updateConfiguration(tmpConfig, dm, compat);
}
@@ -1305,8 +1469,10 @@ public class ResourcesManager {
for (ActivityResources activityResources : mActivityResourceReferences.values()) {
final int resCount = activityResources.activityResources.size();
for (int i = 0; i < resCount; i++) {
- final WeakReference<Resources> ref = activityResources.activityResources.get(i);
- final Resources r = ref != null ? ref.get() : null;
+ final ActivityResource activityResource =
+ activityResources.activityResources.get(i);
+ final Resources r = activityResource != null
+ ? activityResource.resources.get() : null;
if (r != null) {
final ResourcesKey key = updatedResourceKeys.get(r.getImpl());
if (key != null) {
@@ -1338,10 +1504,16 @@ public class ResourcesManager {
if (tokenResources == null) {
return false;
}
- final ArrayList<WeakReference<Resources>> resourcesRefs =
- tokenResources.activityResources;
+ final ArrayList<ActivityResource> resourcesRefs = tokenResources.activityResources;
for (int i = resourcesRefs.size() - 1; i >= 0; i--) {
- final Resources res = resourcesRefs.get(i).get();
+ final ActivityResource activityResource = resourcesRefs.get(i);
+ if (activityResource.overrideDisplayId != null) {
+ // This resource overrides the display of the token so we should not be
+ // modifying its display adjustments here.
+ continue;
+ }
+
+ final Resources res = activityResource.resources.get();
if (res != null) {
res.overrideDisplayAdjustments(override);
handled = true;
diff --git a/core/java/android/app/WindowTokenClient.java b/core/java/android/app/WindowTokenClient.java
index b5d103959818..9092ef36deb6 100644
--- a/core/java/android/app/WindowTokenClient.java
+++ b/core/java/android/app/WindowTokenClient.java
@@ -71,8 +71,7 @@ public class WindowTokenClient extends IWindowToken.Stub {
final boolean configChanged = config.diff(newConfig) != 0;
if (displayChanged || configChanged) {
// TODO(ag/9789103): update resource manager logic to track non-activity tokens
- mResourcesManager.updateResourcesForActivity(this, newConfig, newDisplayId,
- displayChanged);
+ mResourcesManager.updateResourcesForActivity(this, newConfig, newDisplayId);
}
if (displayChanged) {
context.updateDisplay(newDisplayId);
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index d2a774bcb168..c7b20b2a1dc3 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2674,52 +2674,6 @@ public final class BluetoothAdapter {
}
/**
- * Construct an encrypted, RFCOMM server socket.
- * Call #accept to retrieve connections to this socket.
- *
- * @return An RFCOMM BluetoothServerSocket
- * @throws IOException On error, for example Bluetooth not available, or insufficient
- * permissions.
- * @hide
- */
- public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port) throws IOException {
- BluetoothServerSocket socket =
- new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, true, port);
- int errno = socket.mSocket.bindListen();
- if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
- socket.setChannel(socket.mSocket.getPort());
- }
- if (errno < 0) {
- //TODO(BT): Throw the same exception error code
- // that the previous code was using.
- //socket.mSocket.throwErrnoNative(errno);
- throw new IOException("Error: " + errno);
- }
- return socket;
- }
-
- /**
- * Construct a SCO server socket.
- * Call #accept to retrieve connections to this socket.
- *
- * @return A SCO BluetoothServerSocket
- * @throws IOException On error, for example Bluetooth not available, or insufficient
- * permissions.
- * @hide
- */
- public static BluetoothServerSocket listenUsingScoOn() throws IOException {
- BluetoothServerSocket socket =
- new BluetoothServerSocket(BluetoothSocket.TYPE_SCO, false, false, -1);
- int errno = socket.mSocket.bindListen();
- if (errno < 0) {
- //TODO(BT): Throw the same exception error code
- // that the previous code was using.
- //socket.mSocket.throwErrnoNative(errno);
- }
- return socket;
- }
-
- /**
* Construct an encrypted, authenticated, L2CAP server socket.
* Call #accept to retrieve connections to this socket.
* <p>To auto assign a port without creating a SDP record use
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index bed7b26034e5..b7c3289b6e66 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2076,7 +2076,7 @@ public class PackageInstaller {
STAGED_SESSION_VERIFICATION_FAILED,
STAGED_SESSION_ACTIVATION_FAILED,
STAGED_SESSION_UNKNOWN,
- STAGED_SESSION_OTHER_ERROR})
+ STAGED_SESSION_CONFLICT})
@Retention(RetentionPolicy.SOURCE)
public @interface StagedSessionErrorCode{}
/**
@@ -2103,10 +2103,10 @@ public class PackageInstaller {
public static final int STAGED_SESSION_UNKNOWN = 3;
/**
- * Constant indicating that a known error occurred while processing this staged session, but
- * the error could not be matched to other categories.
+ * Constant indicating that the session was in conflict with another staged session and had
+ * to be sacrificed for resolution.
*/
- public static final int STAGED_SESSION_OTHER_ERROR = 4;
+ public static final int STAGED_SESSION_CONFLICT = 4;
/** {@hide} */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 200604801b97..0f1f276ce0f9 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -88,7 +88,6 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.TypedValue;
import android.util.apk.ApkSignatureVerifier;
-import android.view.Display;
import android.view.Gravity;
import com.android.internal.R;
@@ -8536,7 +8535,7 @@ public class PackageParser {
null,
androidAppInfo.resourceDirs,
androidAppInfo.sharedLibraryFiles,
- Display.DEFAULT_DISPLAY,
+ null,
null,
systemResources.getCompatibilityInfo(),
systemResources.getClassLoader(),
diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java
index 9da0f20d1006..fcb80aa3e58d 100644
--- a/core/java/android/content/res/ResourcesKey.java
+++ b/core/java/android/content/res/ResourcesKey.java
@@ -16,6 +16,8 @@
package android.content.res;
+import static android.os.Build.VERSION_CODES.O;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -41,8 +43,17 @@ public final class ResourcesKey {
@Nullable
public final String[] mLibDirs;
- public final int mDisplayId;
-
+ /**
+ * The display ID that overrides the global resources display to produce the Resources display.
+ * If set to something other than {@link android.view.Display#INVALID_DISPLAY} this will
+ * override the global resources display for this key.
+ */
+ @UnsupportedAppUsage(maxTargetSdk = O)
+ public int mDisplayId;
+
+ /**
+ * The configuration applied to the global configuration to produce the Resources configuration.
+ */
@NonNull
public final Configuration mOverrideConfiguration;
@@ -58,7 +69,7 @@ public final class ResourcesKey {
@Nullable String[] splitResDirs,
@Nullable String[] overlayDirs,
@Nullable String[] libDirs,
- int displayId,
+ int overrideDisplayId,
@Nullable Configuration overrideConfig,
@Nullable CompatibilityInfo compatInfo,
@Nullable ResourcesLoader[] loader) {
@@ -67,7 +78,7 @@ public final class ResourcesKey {
mOverlayDirs = overlayDirs;
mLibDirs = libDirs;
mLoaders = (loader != null && loader.length == 0) ? null : loader;
- mDisplayId = displayId;
+ mDisplayId = overrideDisplayId;
mOverrideConfiguration = new Configuration(overrideConfig != null
? overrideConfig : Configuration.EMPTY);
mCompatInfo = compatInfo != null ? compatInfo : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
@@ -77,7 +88,7 @@ public final class ResourcesKey {
hash = 31 * hash + Arrays.hashCode(mSplitResDirs);
hash = 31 * hash + Arrays.hashCode(mOverlayDirs);
hash = 31 * hash + Arrays.hashCode(mLibDirs);
- hash = 31 * hash + mDisplayId;
+ hash = 31 * hash + Objects.hashCode(mDisplayId);
hash = 31 * hash + Objects.hashCode(mOverrideConfiguration);
hash = 31 * hash + Objects.hashCode(mCompatInfo);
hash = 31 * hash + Arrays.hashCode(mLoaders);
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b0d449769be4..fecfd3c2dc7a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2954,7 +2954,7 @@ public abstract class BatteryStats implements Parcelable {
* enough current data to make a decision, or the battery is currently
* charging.
*
- * @param curTime The current elepsed realtime in microseconds.
+ * @param curTime The current elapsed realtime in microseconds.
*/
@UnsupportedAppUsage
public abstract long computeBatteryTimeRemaining(long curTime);
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 1eb3fc11df7b..df1f1b21eba3 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -68,7 +68,7 @@ public class GraphicsEnvironment {
private static final String PROPERTY_GFX_DRIVER_PRERELEASE = "ro.gfx.driver.1";
private static final String PROPERTY_GFX_DRIVER_BUILD_TIME = "ro.gfx.driver_build_time";
private static final String METADATA_DRIVER_BUILD_TIME =
- "com.android.graphics.updatabledriver.build_time";
+ "com.android.graphics.driver.build_time";
private static final String METADATA_DEVELOPER_DRIVER_ENABLE =
"com.android.graphics.developerdriver.enable";
private static final String METADATA_INJECT_LAYERS_ENABLE =
@@ -878,9 +878,10 @@ public class GraphicsEnvironment {
throw new NullPointerException("apk's meta-data cannot be null");
}
- final String driverBuildTime = driverAppInfo.metaData.getString(METADATA_DRIVER_BUILD_TIME);
- if (driverBuildTime == null || driverBuildTime.isEmpty()) {
- Log.v(TAG, "com.android.graphics.updatabledriver.build_time is not set");
+ String driverBuildTime = driverAppInfo.metaData.getString(METADATA_DRIVER_BUILD_TIME);
+ if (driverBuildTime == null || driverBuildTime.length() <= 1) {
+ Log.v(TAG, "com.android.graphics.driver.build_time is not set");
+ driverBuildTime = "L0";
}
// driver_build_time in the meta-data is in "L<Unix epoch timestamp>" format. e.g. L123456.
// Long.parseLong will throw if the meta-data "driver_build_time" is not set properly.
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index ce6c0ffbc10b..a92d91bdefc5 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -18,6 +18,7 @@
package android.os;
import android.os.BatterySaverPolicyConfig;
+import android.os.ParcelDuration;
import android.os.PowerSaveState;
import android.os.WorkSource;
@@ -58,6 +59,9 @@ interface IPowerManager
boolean setAdaptivePowerSavePolicy(in BatterySaverPolicyConfig config);
boolean setAdaptivePowerSaveEnabled(boolean enabled);
int getPowerSaveModeTrigger();
+ void setBatteryDischargePrediction(in ParcelDuration timeRemaining, boolean isCustomized);
+ ParcelDuration getBatteryDischargePrediction();
+ boolean isBatteryDischargePredictionPersonalized();
boolean isDeviceIdleMode();
boolean isLightDeviceIdleMode();
diff --git a/core/java/android/os/ParcelDuration.aidl b/core/java/android/os/ParcelDuration.aidl
new file mode 100644
index 000000000000..e1aa109f14ae
--- /dev/null
+++ b/core/java/android/os/ParcelDuration.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.os;
+
+parcelable ParcelDuration cpp_header "android/ParcelDuration.h"; \ No newline at end of file
diff --git a/core/java/android/os/ParcelDuration.java b/core/java/android/os/ParcelDuration.java
new file mode 100644
index 000000000000..37cde3125cb5
--- /dev/null
+++ b/core/java/android/os/ParcelDuration.java
@@ -0,0 +1,103 @@
+/*
+ * 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 android.os;
+
+import android.annotation.NonNull;
+
+import java.time.Duration;
+
+/**
+ * Parcelable version of {@link Duration} that can be used in binder calls.
+ *
+ * @hide
+ */
+public final class ParcelDuration implements Parcelable {
+
+ private final long mSeconds;
+ private final int mNanos;
+
+ /**
+ * Construct a Duration object using the given millisecond value.
+ *
+ * @hide
+ */
+ public ParcelDuration(long ms) {
+ this(Duration.ofMillis(ms));
+ }
+
+ /**
+ * Wrap a {@link Duration} instance.
+ *
+ * @param duration The {@link Duration} instance to wrap.
+ */
+ public ParcelDuration(@NonNull Duration duration) {
+ mSeconds = duration.getSeconds();
+ mNanos = duration.getNano();
+ }
+
+ private ParcelDuration(@NonNull Parcel parcel) {
+ mSeconds = parcel.readLong();
+ mNanos = parcel.readInt();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int parcelableFlags) {
+ parcel.writeLong(mSeconds);
+ parcel.writeInt(mNanos);
+ }
+
+ /**
+ * Returns a {@link Duration} instance that's equivalent to this Duration's length.
+ *
+ * @return a {@link Duration} instance of identical length.
+ */
+ @NonNull
+ public Duration getDuration() {
+ return Duration.ofSeconds(mSeconds, mNanos);
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return getDuration().toString();
+ }
+
+ /**
+ * Creator for Duration.
+ */
+ @NonNull
+ public static final Parcelable.Creator<ParcelDuration> CREATOR =
+ new Parcelable.Creator<ParcelDuration>() {
+
+ @Override
+ @NonNull
+ public ParcelDuration createFromParcel(@NonNull Parcel source) {
+ return new ParcelDuration(source);
+ }
+
+ @Override
+ @NonNull
+ public ParcelDuration[] newArray(int size) {
+ return new ParcelDuration[size];
+ }
+ };
+}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 309805f14eeb..ed38b3ff78e5 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -41,6 +41,7 @@ import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.time.Duration;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicLong;
@@ -1719,6 +1720,70 @@ public final class PowerManager {
}
/**
+ * Allows an app to tell the system how long it believes the battery will last and whether
+ * this estimate is customized based on historical device usage or on a generic configuration.
+ * These estimates will be displayed on system UI surfaces in place of the system computed
+ * value.
+ *
+ * Calling this requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
+ *
+ * @param timeRemaining The time remaining as a {@link Duration}.
+ * @param isPersonalized true if personalized based on device usage history, false otherwise.
+ * @throws IllegalStateException if the device is powered or currently charging
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+ public void setBatteryDischargePrediction(@NonNull Duration timeRemaining,
+ boolean isPersonalized) {
+ if (timeRemaining == null) {
+ throw new IllegalArgumentException("time remaining must not be null");
+ }
+ try {
+ mService.setBatteryDischargePrediction(new ParcelDuration(timeRemaining),
+ isPersonalized);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the current battery life remaining estimate.
+ *
+ * @return The estimated battery life remaining as a {@link Duration}. Will be {@code null} if
+ * the device is powered, charging, or an error was encountered.
+ */
+ @Nullable
+ public Duration getBatteryDischargePrediction() {
+ try {
+ final ParcelDuration parcelDuration = mService.getBatteryDischargePrediction();
+ if (parcelDuration == null) {
+ return null;
+ }
+ return parcelDuration.getDuration();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether the current battery life remaining estimate is personalized based on device
+ * usage history or not. This value does not take a device's powered or charging state into
+ * account.
+ *
+ * @return A boolean indicating if the current discharge estimate is personalized based on
+ * historical device usage or not.
+ */
+ public boolean isBatteryDischargePredictionPersonalized() {
+ try {
+ return mService.isBatteryDischargePredictionPersonalized();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Get data about the battery saver mode for a specific service
* @param serviceType unique key for the service, one of {@link ServiceType}
* @return Battery saver state data.
@@ -2185,6 +2250,18 @@ public final class PowerManager {
}
/**
+ * Intent that is broadcast when the enhanced battery discharge prediction changes. The new
+ * value can be retrieved via {@link #getBatteryDischargePrediction()}.
+ * This broadcast is only sent to registered receivers.
+ *
+ * @hide
+ */
+ @TestApi
+ @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED =
+ "android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED";
+
+ /**
* Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes.
* This broadcast is only sent to registered receivers.
*/
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 50cc764dd536..58c8efa3a972 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -102,6 +102,8 @@ public final class Trace {
/** @hide */
public static final long TRACE_TAG_RRO = 1L << 26;
/** @hide */
+ public static final long TRACE_TAG_SYSPROP = 1L << 27;
+ /** @hide */
public static final long TRACE_TAG_APEX_MANAGER = 1L << 18;
private static final long TRACE_TAG_NOT_READY = 1L << 63;
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
index 61e6a05fce37..be8b9297ea6a 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -90,9 +90,10 @@ interface IIncrementalService {
int unlink(int storageId, in @utf8InCpp String path);
/**
- * Checks if a file's certain range is loaded. File is specified by its path.
+ * Returns overall loading progress of all the files on a storage, progress value between [0,1].
+ * Returns a negative value on error.
*/
- boolean isFileRangeLoaded(int storageId, in @utf8InCpp String path, long start, long end);
+ float getLoadingProgress(int storageId);
/**
* Reads the metadata of a file. File is specified by either its path or 16 byte id.
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index ca6114f29b9c..b8dbfbb9d109 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -304,29 +304,21 @@ public final class IncrementalStorage {
}
/**
- * Checks whether a file under the current storage directory is fully loaded.
+ * Returns the loading progress of a storage
*
- * @param path The relative path of the file.
- * @return True if the file is fully loaded.
- */
- public boolean isFileFullyLoaded(@NonNull String path) {
- return isFileRangeLoaded(path, 0, -1);
- }
-
- /**
- * Checks whether a range in a file if loaded.
- *
- * @param path The relative path of the file.
- * @param start The starting offset of the range.
- * @param end The ending offset of the range.
- * @return True if the file is fully loaded.
+ * @return progress value between [0, 1].
*/
- public boolean isFileRangeLoaded(@NonNull String path, long start, long end) {
+ public float getLoadingProgress() throws IOException {
try {
- return mService.isFileRangeLoaded(mId, path, start, end);
+ final float res = mService.getLoadingProgress(mId);
+ if (res < 0) {
+ throw new IOException(
+ "getLoadingProgress() failed at querying loading progress, errno " + -res);
+ }
+ return res;
} catch (RemoteException e) {
e.rethrowFromSystemServer();
- return false;
+ return 0;
}
}
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index dfdb57c4e3f8..fb7b2320915c 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -36,8 +36,6 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
import android.widget.TextView;
/**
@@ -337,9 +335,6 @@ public abstract class DialogPreference extends Preference implements
if (state != null) {
dialog.onRestoreInstanceState(state);
}
- if (needInputMethod()) {
- requestInputMethod(dialog);
- }
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
@@ -380,24 +375,6 @@ public abstract class DialogPreference extends Preference implements
}
/**
- * Returns whether the preference needs to display a soft input method when the dialog
- * is displayed. Default is false. Subclasses should override this method if they need
- * the soft input method brought up automatically.
- * @hide
- */
- protected boolean needInputMethod() {
- return false;
- }
-
- /**
- * Sets the required flags on the dialog window to enable input method window to show up.
- */
- private void requestInputMethod(Dialog dialog) {
- Window window = dialog.getWindow();
- window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
- }
-
- /**
* Creates the content view for the dialog (if a custom content view is
* required). By default, it inflates the dialog layout resource if it is
* set.
diff --git a/core/java/android/preference/EditTextPreference.java b/core/java/android/preference/EditTextPreference.java
index af6f18416870..75c5102d04f5 100644
--- a/core/java/android/preference/EditTextPreference.java
+++ b/core/java/android/preference/EditTextPreference.java
@@ -21,6 +21,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -28,6 +29,7 @@ import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
+import android.view.WindowInsets;
import android.widget.EditText;
/**
@@ -123,7 +125,7 @@ public class EditTextPreference extends DialogPreference {
EditText editText = mEditText;
editText.setText(getText());
-
+
ViewParent oldParent = editText.getParent();
if (oldParent != view) {
if (oldParent != null) {
@@ -133,6 +135,13 @@ public class EditTextPreference extends DialogPreference {
}
}
+ @Override
+ protected void showDialog(Bundle state) {
+ super.showDialog(state);
+ mEditText.requestFocus();
+ mEditText.getWindowInsetsController().show(WindowInsets.Type.ime());
+ }
+
/**
* Adds the EditText widget of this preference to the dialog's view.
*
@@ -183,13 +192,6 @@ public class EditTextPreference extends DialogPreference {
return mEditText;
}
- /** @hide */
- @Override
- protected boolean needInputMethod() {
- // We want the input method to show, if possible, when dialog is displayed
- return true;
- }
-
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
diff --git a/core/java/android/preference/OWNERS b/core/java/android/preference/OWNERS
index d20511fcfdf2..827134e8fc9d 100644
--- a/core/java/android/preference/OWNERS
+++ b/core/java/android/preference/OWNERS
@@ -1,2 +1,3 @@
+lpf@google.com
pavlis@google.com
clarabayarri@google.com
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index b45a1eba1e2f..859b70382328 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -197,6 +197,13 @@ public final class DeviceConfig {
"intelligence_content_suggestions";
/**
+ * Namespace for JobScheduler configurations.
+ * @hide
+ */
+ @TestApi
+ public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler";
+
+ /**
* Namespace for all media native related features.
*
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6903a995bf7b..c302def19298 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -65,6 +65,7 @@ import android.os.Bundle;
import android.os.DropBoxManager;
import android.os.IBinder;
import android.os.LocaleList;
+import android.os.PowerManager;
import android.os.PowerManager.AutoPowerSaveModeTriggers;
import android.os.Process;
import android.os.RemoteCallback;
@@ -11844,36 +11845,6 @@ public final class Settings {
public static final String ALARM_MANAGER_CONSTANTS = "alarm_manager_constants";
/**
- * Job scheduler specific settings.
- * This is encoded as a key=value list, separated by commas. Ex:
- *
- * "min_ready_jobs_count=2,moderate_use_factor=.5"
- *
- * The following keys are supported:
- *
- * <pre>
- * min_idle_count (int)
- * min_charging_count (int)
- * min_connectivity_count (int)
- * min_content_count (int)
- * min_ready_jobs_count (int)
- * heavy_use_factor (float)
- * moderate_use_factor (float)
- * fg_job_count (int)
- * bg_normal_job_count (int)
- * bg_moderate_job_count (int)
- * bg_low_job_count (int)
- * bg_critical_job_count (int)
- * </pre>
- *
- * <p>
- * Type: string
- * @hide
- * @see com.android.server.job.JobSchedulerService.Constants
- */
- public static final String JOB_SCHEDULER_CONSTANTS = "job_scheduler_constants";
-
- /**
* Job scheduler QuotaController specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
*
@@ -12545,18 +12516,23 @@ public final class Settings {
* millis. See {@link #BATTERY_ESTIMATES_LAST_UPDATE_TIME} for the last time this value
* was updated.
*
+ * @deprecated Use {@link PowerManager#getBatteryDischargePrediction()} instead.
* @hide
*/
+ @Deprecated
public static final String TIME_REMAINING_ESTIMATE_MILLIS =
"time_remaining_estimate_millis";
/**
- * A boolean indicating whether {@link #TIME_REMAINING_ESTIMATE_MILLIS} is based customized
- * to the devices usage or using global models. See
+ * A boolean indicating whether {@link #TIME_REMAINING_ESTIMATE_MILLIS} is customized
+ * to the device's usage or using global models. See
* {@link #BATTERY_ESTIMATES_LAST_UPDATE_TIME} for the last time this value was updated.
*
+ * @deprecated Use {@link PowerManager#isBatteryDischargePredictionPersonalized()} instead.
+ *
* @hide
*/
+ @Deprecated
public static final String TIME_REMAINING_ESTIMATE_BASED_ON_USAGE =
"time_remaining_estimate_based_on_usage";
@@ -12565,8 +12541,10 @@ public final class Settings {
* average based on historical drain rates. See {@link #BATTERY_ESTIMATES_LAST_UPDATE_TIME}
* for the last time this value was updated.
*
+ * @deprecated Use {@link PowerManager#getHistoricalDischargeTime()} instead.
* @hide
*/
+ @Deprecated
public static final String AVERAGE_TIME_TO_DISCHARGE = "average_time_to_discharge";
/**
@@ -12575,7 +12553,9 @@ public final class Settings {
* and {@link #AVERAGE_TIME_TO_DISCHARGE} were last updated.
*
* @hide
+ * @deprecated No longer needed due to {@link PowerManager#getBatteryDischargePrediction}.
*/
+ @Deprecated
public static final String BATTERY_ESTIMATES_LAST_UPDATE_TIME =
"battery_estimates_last_update_time";
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 678f43daaa38..04a4ca47d305 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -137,7 +137,7 @@ import android.view.autofill.AutofillValue;
* <p>The service can provide an extra degree of security by requiring the user to authenticate
* before an app can be autofilled. The authentication is typically required in 2 scenarios:
* <ul>
- * <li>To unlock the user data (for example, using a master password or fingerprint
+ * <li>To unlock the user data (for example, using a main password or fingerprint
* authentication) - see
* {@link FillResponse.Builder#setAuthentication(AutofillId[], android.content.IntentSender, android.widget.RemoteViews)}.
* <li>To unlock a specific dataset (for example, by providing a CVC for a credit card) - see
@@ -363,9 +363,9 @@ import android.view.autofill.AutofillValue;
* {@code login.some_bank.com} credentials to the {@code my_financial_app}; if the user agrees,
* then the service returns an unlocked dataset with the {@code some_bank.com} credentials.
*
- * <p><b>Note:</b> The autofill service could also whitelist well-known browser apps and skip the
- * verifications above, as long as the service can verify the authenticity of the browser app by
- * checking its signing certificate.
+ * <p><b>Note:</b> The autofill service could also add well-known browser apps into an allowlist and
+ * skip the verifications above, as long as the service can verify the authenticity of the browser
+ * app by checking its signing certificate.
*
* <a name="MultipleStepsSave"></a>
* <h3>Saving when data is split in multiple screens</h3>
@@ -507,9 +507,9 @@ import android.view.autofill.AutofillValue;
* services and fill data. This mode needs to be explicitly requested for a given package up
* to a specified max version code allowing clean migration path when the target app begins to
* support autofill natively. Note that enabling compatibility may degrade performance for the
- * target package and should be used with caution. The platform supports whitelisting which packages
- * can be targeted in compatibility mode to ensure this mode is used only when needed and as long
- * as needed.
+ * target package and should be used with caution. The platform supports creating an allowlist for
+ * including which packages can be targeted in compatibility mode to ensure this mode is used only
+ * when needed and as long as needed.
*
* <p>You can request compatibility mode for packages of interest in the meta-data resource
* associated with your service. Below is a sample service declaration:
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 3fcb36193c60..3ed7f6c517d4 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -62,17 +62,17 @@ import java.util.Set;
* to release the native resources used by the TextToSpeech engine.
*
* Apps targeting Android 11 that use text-to-speech should declare {@link
- * TextToSpeech.Engine#INTENT_ACTION_TTS_SERVICE} in the <code><queries></code> elements of their
+ * TextToSpeech.Engine#INTENT_ACTION_TTS_SERVICE} in the {@code queries} elements of their
* manifest:
*
- * <code>
- * <queries>
+ * <pre>
+ * &lt;queries&gt;
* ...
- * <intent>
- * <action android:name="android.intent.action.TTS_SERVICE" />
- * </intent>
- * </queries>
- * </code>
+ * &lt;intent&gt;
+ * &lt;action android:name="android.intent.action.TTS_SERVICE" /&gt;
+ * &lt;/intent&gt;
+ * &lt;/queries&gt;
+ * </pre>
*/
public class TextToSpeech {
@@ -254,18 +254,17 @@ public class TextToSpeech {
* </ul>
*
* Apps targeting Android 11 that use text-to-speech should declare {@link
- * #INTENT_ACTION_TTS_SERVICE} in the <code><queries></code> elements of their
+ * TextToSpeech.Engine#INTENT_ACTION_TTS_SERVICE} in the {@code queries} elements of their
* manifest:
*
- * <code>
- * <queries>
+ * <pre>
+ * &lt;queries&gt;
* ...
- * <intent>
- * <action android:name="android.intent.action.TTS_SERVICE" />
- * </intent>
- * </queries>
- * </code>
-
+ * &lt;intent&gt;
+ * &lt;action android:name="android.intent.action.TTS_SERVICE" /&gt;
+ * &lt;/intent&gt;
+ * &lt;/queries&gt;
+ * </pre>
*/
public class Engine {
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index a6e6d057d48c..b80718018652 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -938,7 +938,6 @@ public class PhoneStateListener {
* {@link SubscriptionManager#getDefaultSubscriptionId})
* and the value as the list of {@link EmergencyNumber};
* null if this information is not available.
- * @hide
*/
public void onEmergencyNumberListChanged(
@NonNull Map<Integer, List<EmergencyNumber>> emergencyNumberList) {
@@ -948,17 +947,50 @@ public class PhoneStateListener {
/**
* Callback invoked when an outgoing call is placed to an emergency number.
*
- * @param placedEmergencyNumber the emergency number {@link EmergencyNumber} the call is placed
- * to.
+ * This method will be called when an emergency call is placed on any subscription (including
+ * the no-SIM case), regardless of which subscription this listener was registered on.
+ *
+ * This method is deprecated. Both this method and the new
+ * {@link #onOutgoingEmergencyCall(EmergencyNumber, int)} will be called when an outgoing
+ * emergency call is placed.
+ *
+ * @param placedEmergencyNumber The {@link EmergencyNumber} the emergency call was placed to.
+ *
+ * @deprecated Use {@link #onOutgoingEmergencyCall(EmergencyNumber, int)}.
* @hide
*/
@SystemApi
@TestApi
+ @Deprecated
public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber) {
// default implementation empty
}
/**
+ * Callback invoked when an outgoing call is placed to an emergency number.
+ *
+ * This method will be called when an emergency call is placed on any subscription (including
+ * the no-SIM case), regardless of which subscription this listener was registered on.
+ *
+ * Both this method and the deprecated {@link #onOutgoingEmergencyCall(EmergencyNumber)} will be
+ * called when an outgoing emergency call is placed. You should only implement one of these
+ * methods.
+ *
+ * @param placedEmergencyNumber The {@link EmergencyNumber} the emergency call was placed to.
+ * @param subscriptionId The subscription ID used to place the emergency call. If the
+ * emergency call was placed without a valid subscription (e.g. when there
+ * are no SIM cards in the device), this will be equal to
+ * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber,
+ int subscriptionId) {
+ }
+
+ /**
* Callback invoked when an outgoing SMS is placed to an emergency number.
*
* @param sentEmergencyNumber the emergency number {@link EmergencyNumber} the SMS is sent to.
@@ -1336,13 +1368,19 @@ public class PhoneStateListener {
() -> psl.onEmergencyNumberListChanged(emergencyNumberList)));
}
- public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber) {
+ public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber,
+ int subscriptionId) {
PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
if (psl == null) return;
Binder.withCleanCallingIdentity(
() -> mExecutor.execute(
() -> psl.onOutgoingEmergencyCall(placedEmergencyNumber)));
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(
+ () -> psl.onOutgoingEmergencyCall(placedEmergencyNumber,
+ subscriptionId)));
}
public void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber) {
diff --git a/core/java/android/text/OWNERS b/core/java/android/text/OWNERS
index e56137119c28..0b51b2d90b79 100644
--- a/core/java/android/text/OWNERS
+++ b/core/java/android/text/OWNERS
@@ -1,5 +1,4 @@
set noparent
siyamed@google.com
-nona@google.com
-clarabayarri@google.com
+nona@google.com \ No newline at end of file
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index 25a4108c612c..a06a0c68e241 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -25,6 +25,7 @@ import android.util.SparseIntArray;
import dalvik.system.CloseGuard;
+import java.io.PrintWriter;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
@@ -53,6 +54,7 @@ public abstract class InputEventReceiver {
private static native void nativeFinishInputEvent(long receiverPtr, int seq, boolean handled);
private static native boolean nativeConsumeBatchedInputEvents(long receiverPtr,
long frameTimeNanos);
+ private static native String nativeDump(long receiverPtr, String prefix);
/**
* Creates an input event receiver bound to the specified input channel.
@@ -221,6 +223,18 @@ public abstract class InputEventReceiver {
}
/**
+ * Dump the state of this InputEventReceiver to the writer.
+ * @param prefix the prefix (typically whitespace padding) to append in front of each line
+ * @param writer the writer where the dump should be written
+ */
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + getClass().getName());
+ writer.println(prefix + " mInputChannel: " + mInputChannel);
+ writer.println(prefix + " mSeqMap: " + mSeqMap);
+ writer.println(prefix + " mReceiverPtr:\n" + nativeDump(mReceiverPtr, prefix + " "));
+ }
+
+ /**
* Factory for InputEventReceiver
*/
public interface Factory {
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index e341845277d4..1ef701f732ff 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -70,11 +70,8 @@ public final class InputWindowHandle {
// Window is visible.
public boolean visible;
- // Window can receive keys.
- public boolean canReceiveKeys;
-
- // Window has focus.
- public boolean hasFocus;
+ // Window can be focused.
+ public boolean focusable;
// Window has wallpaper. (window is the current wallpaper target)
public boolean hasWallpaper;
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 7f45c044408a..403ac3ab29c0 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -629,7 +629,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged");
mHost.notifyInsetsChanged();
}
- if (!mState.equals(state, true /* excludingCaptionInsets */,
+ if (!mState.equals(mLastDispatchedState, true /* excludingCaptionInsets */,
true /* excludeInvisibleIme */)) {
if (DEBUG) Log.d(TAG, "onStateChanged, send state to WM: " + mState);
updateRequestedState();
@@ -1138,15 +1138,14 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (invokeCallback) {
control.cancel();
}
+ boolean stateChanged = false;
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
if (runningAnimation.runner == control) {
mRunningAnimations.remove(i);
ArraySet<Integer> types = toInternalType(control.getTypes());
for (int j = types.size() - 1; j >= 0; j--) {
- if (getSourceConsumer(types.valueAt(j)).notifyAnimationFinished()) {
- mHost.notifyInsetsChanged();
- }
+ stateChanged |= getSourceConsumer(types.valueAt(j)).notifyAnimationFinished();
}
if (invokeCallback && runningAnimation.startDispatched) {
dispatchAnimationEnd(runningAnimation.runner.getAnimation());
@@ -1154,6 +1153,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
break;
}
}
+ if (stateChanged) {
+ mHost.notifyInsetsChanged();
+ updateRequestedState();
+ }
}
private void applyLocalVisibilityOverride() {
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 6b0b509932a8..593b37af26ad 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -60,6 +60,8 @@ import java.util.StringJoiner;
*/
public class InsetsState implements Parcelable {
+ public static final InsetsState EMPTY = new InsetsState();
+
/**
* Internal representation of inset source types. This is different from the public API in
* {@link WindowInsets.Type} as one type from the public API might indicate multiple windows
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 859e9a43f7c2..65cc2f8bcd5a 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -19,6 +19,7 @@ package android.view;
import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
+import android.annotation.FloatRange;
import android.graphics.RenderNode;
import java.util.ArrayList;
@@ -725,7 +726,7 @@ public class ViewPropertyAnimator {
* @see View#setAlpha(float)
* @return This object, allowing calls to methods in this class to be chained.
*/
- public ViewPropertyAnimator alpha(float value) {
+ public ViewPropertyAnimator alpha(@FloatRange(from = 0.0f, to = 1.0f) float value) {
animateProperty(ALPHA, value);
return this;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3f02d701f71f..6e17ac9960a8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -7532,36 +7532,36 @@ public final class ViewRootImpl implements ViewParent,
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
String innerPrefix = prefix + " ";
- writer.print(prefix); writer.println("ViewRoot:");
- writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
- writer.print(" mRemoved="); writer.println(mRemoved);
- writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
- writer.println(mConsumeBatchedInputScheduled);
- writer.print(innerPrefix); writer.print("mConsumeBatchedInputImmediatelyScheduled=");
- writer.println(mConsumeBatchedInputImmediatelyScheduled);
- writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
- writer.println(mPendingInputEventCount);
- writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
- writer.println(mProcessInputEventsScheduled);
- writer.print(innerPrefix); writer.print("mTraversalScheduled=");
- writer.print(mTraversalScheduled);
- writer.print(innerPrefix); writer.print("mIsAmbientMode=");
- writer.print(mIsAmbientMode);
- writer.print(innerPrefix); writer.print("mUnbufferedInputSource=");
- writer.print(Integer.toHexString(mUnbufferedInputSource));
-
+ writer.println(prefix + "ViewRoot:");
+ writer.println(innerPrefix + "mAdded=" + mAdded);
+ writer.println(innerPrefix + "mRemoved=" + mRemoved);
+ writer.println(innerPrefix + "mStopped=" + mStopped);
+ writer.println(innerPrefix + "mConsumeBatchedInputScheduled="
+ + mConsumeBatchedInputScheduled);
+ writer.println(innerPrefix + "mConsumeBatchedInputImmediatelyScheduled="
+ + mConsumeBatchedInputImmediatelyScheduled);
+ writer.println(innerPrefix + "mPendingInputEventCount=" + mPendingInputEventCount);
+ writer.println(innerPrefix + "mProcessInputEventsScheduled="
+ + mProcessInputEventsScheduled);
+ writer.println(innerPrefix + "mTraversalScheduled=" + mTraversalScheduled);
if (mTraversalScheduled) {
- writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
- } else {
- writer.println();
+ writer.println(innerPrefix + " (barrier=" + mTraversalBarrier + ")");
}
+ writer.println(innerPrefix + "mIsAmbientMode=" + mIsAmbientMode);
+ writer.println(innerPrefix + "mUnbufferedInputSource="
+ + Integer.toHexString(mUnbufferedInputSource));
+
mFirstInputStage.dump(innerPrefix, writer);
+ if (mInputEventReceiver != null) {
+ mInputEventReceiver.dump(innerPrefix, writer);
+ }
+
mChoreographer.dump(prefix, writer);
mInsetsController.dump(prefix, writer);
- writer.print(prefix); writer.println("View Hierarchy:");
+ writer.println(prefix + "View Hierarchy:");
dumpViewHierarchy(innerPrefix, writer, mView);
}
@@ -8890,6 +8890,9 @@ public final class ViewRootImpl implements ViewParent,
* @param targets the search queue for targets
*/
private void collectRootScrollCaptureTargets(Queue<ScrollCaptureTarget> targets) {
+ if (mRootScrollCaptureCallbacks == null) {
+ return;
+ }
for (ScrollCaptureCallback cb : mRootScrollCaptureCallbacks) {
// Add to the list for consideration
Point offset = new Point(mView.getLeft(), mView.getTop());
diff --git a/core/java/android/webkit/PacProcessor.java b/core/java/android/webkit/PacProcessor.java
index 7e7b987f72f3..b04105ab1e75 100644
--- a/core/java/android/webkit/PacProcessor.java
+++ b/core/java/android/webkit/PacProcessor.java
@@ -32,6 +32,10 @@ public interface PacProcessor {
/**
* Returns the default PacProcessor instance.
*
+ * <p> There can only be one default {@link PacProcessor} instance.
+ * This method will create a new instance if one did not already exist, or
+ * if the previous instance was released with {@link #releasePacProcessor}.
+ *
* @return the default PacProcessor instance.
*/
@NonNull
@@ -43,14 +47,21 @@ public interface PacProcessor {
* Returns PacProcessor instance associated with the {@link Network}.
* The host resolution is done on this {@link Network}.
*
- * @param networkHandle a handle representing {@link Network} handle.
- * @return PacProcessor instance for the specified network.
- * @see Network#getNetworkHandle
- * @see Network#fromNetworkHandle
+ * <p> There can only be one {@link PacProcessor} instance at a time for each {@link Network}.
+ * This method will create a new instance if one did not already exist, or
+ * if the previous instance was released with {@link #releasePacProcessor}.
+ *
+ * <p> The {@link PacProcessor} instance needs to be released manually with
+ * {@link #releasePacProcessor} when the associated {@link Network} goes away.
+ *
+ * @param network a {@link Network} which this {@link PacProcessor}
+ * will use for host/address resolution.
+ * If {@code null} this method is equivalent to {@link #getInstance}.
+ * @return {@link PacProcessor} instance for the specified network.
*/
@NonNull
- static PacProcessor getInstanceForNetwork(long networkHandle) {
- return WebViewFactory.getProvider().getPacProcessorForNetwork(networkHandle);
+ static PacProcessor getInstanceForNetwork(@Nullable Network network) {
+ return WebViewFactory.getProvider().getPacProcessorForNetwork(network);
}
/**
@@ -73,19 +84,22 @@ public interface PacProcessor {
/**
* Stops support for this {@link PacProcessor} and release its resources.
* No methods of this class must be called after calling this method.
+ *
+ * <p> Released instances will not be reused; a subsequent call to
+ * {@link #getInstance} and {@link #getInstanceForNetwork}
+ * for the same network will create a new instance.
*/
default void releasePacProcessor() {
throw new UnsupportedOperationException("Not implemented");
}
/**
- * Returns a network handle associated with this {@link PacProcessor}.
+ * Returns a {@link Network} associated with this {@link PacProcessor}.
*
- * @return a network handle or 0 if a network is unspecified.
- * @see Network#getNetworkHandle
- * @see Network#fromNetworkHandle
+ * @return an associated {@link Network} or {@code null} if a network is unspecified.
*/
- default long getNetworkHandle() {
+ @Nullable
+ default Network getNetwork() {
throw new UnsupportedOperationException("Not implemented");
}
}
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index f1863e319689..ce999cd5e235 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
@@ -188,13 +189,13 @@ public interface WebViewFactoryProvider {
* Returns PacProcessor instance associated with the {@link Network}.
* The host resolution is done on this {@link Network}.
*
- * @param networkHandle a network handle representing the {@link Network}.
+ * @param network a {@link Network} which needs to be associated
+ * with the returned {@link PacProcessor}.
+ * If {@code null} the method returns default {@link PacProcessor}.
* @return the {@link PacProcessor} instance associated with {@link Network}.
- * @see Network#getNetworkHandle
- * @see Network#fromNetworkHandle
*/
@NonNull
- default PacProcessor getPacProcessorForNetwork(long networkHandle) {
+ default PacProcessor getPacProcessorForNetwork(@Nullable Network network) {
throw new UnsupportedOperationException("Not implemented");
}
diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl
index 1c03b2fdf906..92fa80e40caf 100644
--- a/core/java/android/window/ITaskOrganizerController.aidl
+++ b/core/java/android/window/ITaskOrganizerController.aidl
@@ -25,11 +25,9 @@ import android.window.WindowContainerTransaction;
interface ITaskOrganizerController {
/**
- * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
- * If there was already a TaskOrganizer for this windowing mode it will be evicted
- * and receive taskVanished callbacks in the process.
+ * Register a TaskOrganizer to manage all the tasks with supported windowing modes.
*/
- void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode);
+ void registerTaskOrganizer(ITaskOrganizer organizer);
/**
* Unregisters a previously registered task organizer.
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 502680de9bcf..7ec4f99ce959 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -36,14 +36,12 @@ import java.util.List;
public class TaskOrganizer extends WindowOrganizer {
/**
- * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
- * If there was already a TaskOrganizer for this windowing mode it will be evicted
- * and receive taskVanished callbacks in the process.
+ * Register a TaskOrganizer to manage tasks as they enter a supported windowing mode.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public final void registerOrganizer(int windowingMode) {
+ public final void registerOrganizer() {
try {
- getController().registerTaskOrganizer(mInterface, windowingMode);
+ getController().registerTaskOrganizer(mInterface);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/window/TaskOrganizerTaskEmbedder.java b/core/java/android/window/TaskOrganizerTaskEmbedder.java
index 1b87521f3a96..46c72f88e14b 100644
--- a/core/java/android/window/TaskOrganizerTaskEmbedder.java
+++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java
@@ -73,7 +73,7 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder {
// TODO(wm-shell): This currently prevents other organizers from controlling MULT_WINDOW
// windowing mode tasks. Plan is to migrate this to a wm-shell front-end when that
// infrastructure is ready.
- mTaskOrganizer.registerOrganizer(WINDOWING_MODE_MULTI_WINDOW);
+ // mTaskOrganizer.registerOrganizer();
mTaskOrganizer.setInterceptBackPressedOnTaskRoot(true);
return super.onInitialize();
diff --git a/core/java/com/android/internal/os/TEST_MAPPING b/core/java/com/android/internal/os/TEST_MAPPING
index f44b9fb7e723..9698f190a419 100644
--- a/core/java/com/android/internal/os/TEST_MAPPING
+++ b/core/java/com/android/internal/os/TEST_MAPPING
@@ -26,5 +26,20 @@
"KernelSingleUidTimeReader\\.java"
]
}
+ ],
+ "postsubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "com.android.internal.os.BstatsCpuTimesValidationTest"
+ }
+ ],
+ "file_patterns": [
+ "BatteryStatsImpl\\.java",
+ "KernelCpuUidFreqTimeReader\\.java",
+ "KernelSingleUidTimeReader\\.java"
+ ]
+ }
]
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 053b06f3d407..2f8c45770eb5 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -347,7 +347,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
super(context);
mLayoutInflater = LayoutInflater.from(context);
mRenderShadowsInCompositor = Settings.Global.getInt(context.getContentResolver(),
- DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 0) != 0;
+ DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 1) != 0;
}
/**
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index b2c5a998e254..d41d30735d7d 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -61,7 +61,7 @@ oneway interface IPhoneStateListener {
void onRadioPowerStateChanged(in int state);
void onCallAttributesChanged(in CallAttributes callAttributes);
void onEmergencyNumberListChanged(in Map emergencyNumberList);
- void onOutgoingEmergencyCall(in EmergencyNumber placedEmergencyNumber);
+ void onOutgoingEmergencyCall(in EmergencyNumber placedEmergencyNumber, int subscriptionId);
void onOutgoingEmergencySms(in EmergencyNumber sentEmergencyNumber);
void onCallDisconnectCauseChanged(in int disconnectCause, in int preciseDisconnectCause);
void onImsCallDisconnectCauseChanged(in ImsReasonInfo imsReasonInfo);
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index c82a6564c1d7..937b9426476a 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -200,6 +200,20 @@ public class Preconditions {
}
/**
+ * Ensures the truth of an expression involving whether the calling identity is authorized to
+ * call the calling method.
+ *
+ * @param expression a boolean expression
+ * @param message the message of the security exception to be thrown
+ * @throws SecurityException if {@code expression} is false
+ */
+ public static void checkSecurity(final boolean expression, final String message) {
+ if (!expression) {
+ throw new SecurityException(message);
+ }
+ }
+
+ /**
* Ensures the truth of an expression involving whether the calling user is authorized to
* call the calling method.
*
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index d5d635de81d8..654b46164dcf 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -49,7 +49,8 @@ interface ILockSettings {
in ICheckCredentialProgressCallback progressCallback);
VerifyCredentialResponse verifyCredential(in LockscreenCredential credential, int userId, int flags);
VerifyCredentialResponse verifyTiedProfileChallenge(in LockscreenCredential credential, int userId, int flags);
- VerifyCredentialResponse verifyGatekeeperPassword(in byte[] gatekeeperPassword, long challenge, int userId);
+ VerifyCredentialResponse verifyGatekeeperPasswordHandle(long gatekeeperPasswordHandle, long challenge, int userId);
+ void removeGatekeeperPasswordHandle(long gatekeeperPasswordHandle);
boolean checkVoldPassword(int userId);
int getCredentialType(int userId);
byte[] getHashFactor(in LockscreenCredential currentCredential, int userId);
diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java
index 2302de2cd058..b4e108faee2d 100644
--- a/core/java/com/android/internal/widget/LocalImageResolver.java
+++ b/core/java/com/android/internal/widget/LocalImageResolver.java
@@ -23,6 +23,7 @@ import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
@@ -31,6 +32,7 @@ import java.io.InputStream;
* A class to extract Bitmaps from a MessagingStyle message.
*/
public class LocalImageResolver {
+ private static final String TAG = LocalImageResolver.class.getSimpleName();
private static final int MAX_SAFE_ICON_SIZE_PX = 480;
@@ -60,11 +62,18 @@ public class LocalImageResolver {
private static BitmapFactory.Options getBoundsOptionsForImage(Uri uri, Context context)
throws IOException {
- InputStream input = context.getContentResolver().openInputStream(uri);
BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
- onlyBoundsOptions.inJustDecodeBounds = true;
- BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
- input.close();
+ try (InputStream input = context.getContentResolver().openInputStream(uri)) {
+ if (input == null) {
+ throw new IllegalArgumentException();
+ }
+ onlyBoundsOptions.inJustDecodeBounds = true;
+ BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
+ } catch (IllegalArgumentException iae) {
+ onlyBoundsOptions.outWidth = -1;
+ onlyBoundsOptions.outHeight = -1;
+ Log.e(TAG, "error loading image", iae);
+ }
return onlyBoundsOptions;
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f7370d6a22f9..08a9f48ec0b4 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -130,14 +130,15 @@ public class LockPatternUtils {
public @interface CredentialType {}
/**
- * Flag provided to {@link #verifyCredential(LockscreenCredential, long, int, int)} . If set,
- * the method will return the Gatekeeper Password in the {@link VerifyCredentialResponse}.
+ * Flag provided to {@link #verifyCredential(LockscreenCredential, int, int)} . If set, the
+ * method will return a handle to the Gatekeeper Password in the
+ * {@link VerifyCredentialResponse}.
*/
- public static final int VERIFY_FLAG_RETURN_GK_PW = 1 << 0;
+ public static final int VERIFY_FLAG_REQUEST_GK_PW_HANDLE = 1 << 0;
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, value = {
- VERIFY_FLAG_RETURN_GK_PW
+ VERIFY_FLAG_REQUEST_GK_PW_HANDLE
})
public @interface VerifyFlag {}
@@ -409,16 +410,16 @@ public class LockPatternUtils {
}
/**
- * With the Gatekeeper Password returned via {@link #verifyCredential(LockscreenCredential,
- * int, int)}, request Gatekeeper to create a HardwareAuthToken wrapping the given
- * challenge.
+ * With the Gatekeeper Password Handle returned via {@link #verifyCredential(
+ * LockscreenCredential, int, int)}, request Gatekeeper to create a HardwareAuthToken wrapping
+ * the given challenge.
*/
@NonNull
- public VerifyCredentialResponse verifyGatekeeperPassword(@NonNull byte[] gatekeeperPassword,
+ public VerifyCredentialResponse verifyGatekeeperPasswordHandle(long gatekeeperPasswordHandle,
long challenge, int userId) {
try {
- final VerifyCredentialResponse response = getLockSettings().verifyGatekeeperPassword(
- gatekeeperPassword, challenge, userId);
+ final VerifyCredentialResponse response = getLockSettings()
+ .verifyGatekeeperPasswordHandle(gatekeeperPasswordHandle, challenge, userId);
if (response == null) {
return VerifyCredentialResponse.ERROR;
}
@@ -429,6 +430,14 @@ public class LockPatternUtils {
}
}
+ public void removeGatekeeperPasswordHandle(long gatekeeperPasswordHandle) {
+ try {
+ getLockSettings().removeGatekeeperPasswordHandle(gatekeeperPasswordHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to remove gatekeeper password handle", e);
+ }
+ }
+
/**
* Check to see if a credential matches the saved one.
*
@@ -671,7 +680,7 @@ public class LockPatternUtils {
*/
public boolean setLockCredential(@NonNull LockscreenCredential newCredential,
@NonNull LockscreenCredential savedCredential, int userHandle) {
- if (!hasSecureLockScreen()) {
+ if (!hasSecureLockScreen() && newCredential.getType() != CREDENTIAL_TYPE_NONE) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
}
@@ -766,7 +775,7 @@ public class LockPatternUtils {
/** Update the encryption password if it is enabled **/
private void updateEncryptionPassword(final int type, final byte[] password) {
- if (!hasSecureLockScreen()) {
+ if (!hasSecureLockScreen() && password != null && password.length != 0) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
}
@@ -1566,7 +1575,7 @@ public class LockPatternUtils {
*/
public boolean setLockCredentialWithToken(@NonNull LockscreenCredential credential,
long tokenHandle, byte[] token, int userHandle) {
- if (!hasSecureLockScreen()) {
+ if (!hasSecureLockScreen() && credential.getType() != CREDENTIAL_TYPE_NONE) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
}
diff --git a/core/java/com/android/internal/widget/VerifyCredentialResponse.java b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
index e09eb4228219..ab146341cbaa 100644
--- a/core/java/com/android/internal/widget/VerifyCredentialResponse.java
+++ b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
@@ -49,7 +49,7 @@ public final class VerifyCredentialResponse implements Parcelable {
private final @ResponseCode int mResponseCode;
private final int mTimeout;
@Nullable private final byte[] mGatekeeperHAT;
- @Nullable private final byte[] mGatekeeperPw;
+ private final long mGatekeeperPasswordHandle;
public static final Parcelable.Creator<VerifyCredentialResponse> CREATOR
= new Parcelable.Creator<VerifyCredentialResponse>() {
@@ -58,10 +58,10 @@ public final class VerifyCredentialResponse implements Parcelable {
final @ResponseCode int responseCode = source.readInt();
final int timeout = source.readInt();
final byte[] gatekeeperHAT = source.createByteArray();
- final byte[] gatekeeperPassword = source.createByteArray();
+ long gatekeeperPasswordHandle = source.readLong();
return new VerifyCredentialResponse(responseCode, timeout, gatekeeperHAT,
- gatekeeperPassword);
+ gatekeeperPasswordHandle);
}
@Override
@@ -72,7 +72,7 @@ public final class VerifyCredentialResponse implements Parcelable {
public static class Builder {
@Nullable private byte[] mGatekeeperHAT;
- @Nullable private byte[] mGatekeeperPassword;
+ private long mGatekeeperPasswordHandle;
/**
* @param gatekeeperHAT Gatekeeper HardwareAuthToken, minted upon successful authentication.
@@ -82,8 +82,8 @@ public final class VerifyCredentialResponse implements Parcelable {
return this;
}
- public Builder setGatekeeperPassword(byte[] gatekeeperPassword) {
- mGatekeeperPassword = gatekeeperPassword;
+ public Builder setGatekeeperPasswordHandle(long gatekeeperPasswordHandle) {
+ mGatekeeperPasswordHandle = gatekeeperPasswordHandle;
return this;
}
@@ -96,7 +96,7 @@ public final class VerifyCredentialResponse implements Parcelable {
return new VerifyCredentialResponse(RESPONSE_OK,
0 /* timeout */,
mGatekeeperHAT,
- mGatekeeperPassword);
+ mGatekeeperPasswordHandle);
}
}
@@ -110,7 +110,7 @@ public final class VerifyCredentialResponse implements Parcelable {
return new VerifyCredentialResponse(RESPONSE_RETRY,
timeout,
null /* gatekeeperHAT */,
- null /* gatekeeperPassword */);
+ 0L /* gatekeeperPasswordHandle */);
}
/**
@@ -121,20 +121,20 @@ public final class VerifyCredentialResponse implements Parcelable {
return new VerifyCredentialResponse(RESPONSE_ERROR,
0 /* timeout */,
null /* gatekeeperHAT */,
- null /* gatekeeperPassword */);
+ 0L /* gatekeeperPasswordHandle */);
}
private VerifyCredentialResponse(@ResponseCode int responseCode, int timeout,
- @Nullable byte[] gatekeeperHAT, @Nullable byte[] gatekeeperPassword) {
+ @Nullable byte[] gatekeeperHAT, long gatekeeperPasswordHandle) {
mResponseCode = responseCode;
mTimeout = timeout;
mGatekeeperHAT = gatekeeperHAT;
- mGatekeeperPw = gatekeeperPassword;
+ mGatekeeperPasswordHandle = gatekeeperPasswordHandle;
}
public VerifyCredentialResponse stripPayload() {
return new VerifyCredentialResponse(mResponseCode, mTimeout,
- null /* gatekeeperHAT */, null /* gatekeeperPassword */);
+ null /* gatekeeperHAT */, 0L /* gatekeeperPasswordHandle */);
}
@Override
@@ -142,7 +142,7 @@ public final class VerifyCredentialResponse implements Parcelable {
dest.writeInt(mResponseCode);
dest.writeInt(mTimeout);
dest.writeByteArray(mGatekeeperHAT);
- dest.writeByteArray(mGatekeeperPw);
+ dest.writeLong(mGatekeeperPasswordHandle);
}
@Override
@@ -155,9 +155,12 @@ public final class VerifyCredentialResponse implements Parcelable {
return mGatekeeperHAT;
}
- @Nullable
- public byte[] getGatekeeperPw() {
- return mGatekeeperPw;
+ public long getGatekeeperPasswordHandle() {
+ return mGatekeeperPasswordHandle;
+ }
+
+ public boolean containsGatekeeperPasswordHandle() {
+ return mGatekeeperPasswordHandle != 0L;
}
public int getTimeout() {
@@ -176,7 +179,7 @@ public final class VerifyCredentialResponse implements Parcelable {
public String toString() {
return "Response: " + mResponseCode
+ ", GK HAT: " + (mGatekeeperHAT != null)
- + ", GK PW: " + (mGatekeeperPw != null);
+ + ", GK PW: " + (mGatekeeperPasswordHandle != 0L);
}
public static VerifyCredentialResponse fromGateKeeperResponse(
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index ecdba3fcb023..a0638207a841 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -56,8 +56,7 @@ static struct {
jfieldID scaleFactor;
jfieldID touchableRegion;
jfieldID visible;
- jfieldID canReceiveKeys;
- jfieldID hasFocus;
+ jfieldID focusable;
jfieldID hasWallpaper;
jfieldID paused;
jfieldID trustedOverlay;
@@ -145,10 +144,7 @@ bool NativeInputWindowHandle::updateInfo() {
mInfo.visible = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.visible);
- mInfo.canReceiveKeys = env->GetBooleanField(obj,
- gInputWindowHandleClassInfo.canReceiveKeys);
- mInfo.hasFocus = env->GetBooleanField(obj,
- gInputWindowHandleClassInfo.hasFocus);
+ mInfo.focusable = env->GetBooleanField(obj, gInputWindowHandleClassInfo.focusable);
mInfo.hasWallpaper = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.hasWallpaper);
mInfo.paused = env->GetBooleanField(obj,
@@ -320,11 +316,7 @@ int register_android_view_InputWindowHandle(JNIEnv* env) {
GET_FIELD_ID(gInputWindowHandleClassInfo.visible, clazz,
"visible", "Z");
- GET_FIELD_ID(gInputWindowHandleClassInfo.canReceiveKeys, clazz,
- "canReceiveKeys", "Z");
-
- GET_FIELD_ID(gInputWindowHandleClassInfo.hasFocus, clazz,
- "hasFocus", "Z");
+ GET_FIELD_ID(gInputWindowHandleClassInfo.focusable, clazz, "focusable", "Z");
GET_FIELD_ID(gInputWindowHandleClassInfo.hasWallpaper, clazz,
"hasWallpaper", "Z");
diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp
index f8f841c6fd26..3af55fe810fc 100644
--- a/core/jni/android_os_HwRemoteBinder.cpp
+++ b/core/jni/android_os_HwRemoteBinder.cpp
@@ -269,22 +269,9 @@ jobject JHwRemoteBinder::NewObject(
return obj;
}
-JHwRemoteBinder::JHwRemoteBinder(
- JNIEnv *env, jobject thiz, const sp<hardware::IBinder> &binder)
- : mBinder(binder) {
- mDeathRecipientList = new HwBinderDeathRecipientList();
- jclass clazz = env->GetObjectClass(thiz);
- CHECK(clazz != NULL);
-
- mObject = env->NewWeakGlobalRef(thiz);
-}
-
-JHwRemoteBinder::~JHwRemoteBinder() {
- JNIEnv *env = AndroidRuntime::getJNIEnv();
-
- env->DeleteWeakGlobalRef(mObject);
- mObject = NULL;
-}
+JHwRemoteBinder::JHwRemoteBinder(JNIEnv* env, jobject /* thiz */,
+ const sp<hardware::IBinder>& binder)
+ : mBinder(binder), mDeathRecipientList(new HwBinderDeathRecipientList()) {}
sp<hardware::IBinder> JHwRemoteBinder::getBinder() const {
return mBinder;
diff --git a/core/jni/android_os_HwRemoteBinder.h b/core/jni/android_os_HwRemoteBinder.h
index 4b5a4c8c837c..7eb81f3c54e1 100644
--- a/core/jni/android_os_HwRemoteBinder.h
+++ b/core/jni/android_os_HwRemoteBinder.h
@@ -36,9 +36,13 @@ class HwBinderDeathRecipientList : public RefBase {
std::vector<sp<HwBinderDeathRecipient>> mList;
Mutex mLock;
+protected:
+ ~HwBinderDeathRecipientList() override;
+
public:
- HwBinderDeathRecipientList();
- ~HwBinderDeathRecipientList();
+ explicit HwBinderDeathRecipientList();
+
+ DISALLOW_COPY_AND_ASSIGN(HwBinderDeathRecipientList);
void add(const sp<HwBinderDeathRecipient>& recipient);
void remove(const sp<HwBinderDeathRecipient>& recipient);
@@ -66,12 +70,7 @@ struct JHwRemoteBinder : public RefBase {
void setBinder(const sp<hardware::IBinder> &binder);
sp<HwBinderDeathRecipientList> getDeathRecipientList() const;
-protected:
- virtual ~JHwRemoteBinder();
-
private:
- jobject mObject;
-
sp<hardware::IBinder> mBinder;
sp<HwBinderDeathRecipientList> mDeathRecipientList;
DISALLOW_COPY_AND_ASSIGN(JHwRemoteBinder);
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 979a69aa3ce2..9ed71ac0fb7b 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -22,11 +22,12 @@
#include <nativehelper/JNIHelp.h>
+#include <android-base/stringprintf.h>
#include <android_runtime/AndroidRuntime.h>
+#include <input/InputTransport.h>
#include <log/log.h>
#include <utils/Looper.h>
-#include <utils/Vector.h>
-#include <input/InputTransport.h>
+#include <vector>
#include "android_os_MessageQueue.h"
#include "android_view_InputChannel.h"
#include "android_view_KeyEvent.h"
@@ -52,6 +53,21 @@ static struct {
jmethodID onBatchedInputEventPending;
} gInputEventReceiverClassInfo;
+// Add prefix to the beginning of each line in 'str'
+static std::string addPrefix(std::string str, std::string_view prefix) {
+ str.insert(0, prefix); // insert at the beginning of the first line
+ const size_t prefixLength = prefix.length();
+ size_t pos = prefixLength; // just inserted prefix. start at the end of it
+ while (true) { // process all newline characters in 'str'
+ pos = str.find('\n', pos);
+ if (pos == std::string::npos) {
+ break;
+ }
+ str.insert(pos + 1, prefix); // insert prefix just after the '\n' character
+ pos += prefixLength + 1; // advance the position past the newly inserted prefix
+ }
+ return str;
+}
class NativeInputEventReceiver : public LooperCallback {
public:
@@ -64,6 +80,7 @@ public:
status_t finishInputEvent(uint32_t seq, bool handled);
status_t consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime,
bool* outConsumedBatch);
+ std::string dump(const char* prefix);
protected:
virtual ~NativeInputEventReceiver();
@@ -80,7 +97,7 @@ private:
PreallocatedInputEventFactory mInputEventFactory;
bool mBatchedInputEventPending;
int mFdEvents;
- Vector<Finish> mFinishQueue;
+ std::vector<Finish> mFinishQueue;
void setFdEvents(int events);
@@ -128,7 +145,7 @@ status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled)
}
status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
- if (status) {
+ if (status != OK) {
if (status == WOULD_BLOCK) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Could not send finished signal immediately. "
@@ -137,7 +154,7 @@ status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled)
Finish finish;
finish.seq = seq;
finish.handled = handled;
- mFinishQueue.add(finish);
+ mFinishQueue.push_back(finish);
if (mFinishQueue.size() == 1) {
setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT);
}
@@ -162,6 +179,9 @@ void NativeInputEventReceiver::setFdEvents(int events) {
}
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
+ // Allowed return values of this function as documented in LooperCallback::handleEvent
+ constexpr int REMOVE_CALLBACK = 0;
+ constexpr int KEEP_CALLBACK = 1;
if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
// This error typically occurs when the publisher has closed the input channel
// as part of removing a window or finishing an IME session, in which case
@@ -170,41 +190,42 @@ int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data)
ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. "
"events=0x%x", getInputChannelName().c_str(), events);
}
- return 0; // remove the callback
+ return REMOVE_CALLBACK;
}
if (events & ALOOPER_EVENT_INPUT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
- return status == OK || status == NO_MEMORY ? 1 : 0;
+ return status == OK || status == NO_MEMORY ? KEEP_CALLBACK : REMOVE_CALLBACK;
}
if (events & ALOOPER_EVENT_OUTPUT) {
for (size_t i = 0; i < mFinishQueue.size(); i++) {
- const Finish& finish = mFinishQueue.itemAt(i);
+ const Finish& finish = mFinishQueue[i];
status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);
- if (status) {
- mFinishQueue.removeItemsAt(0, i);
+ if (status != OK) {
+ mFinishQueue.erase(mFinishQueue.begin(), mFinishQueue.begin() + i);
if (status == WOULD_BLOCK) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Sent %zu queued finish events; %zu left.",
- getInputChannelName().c_str(), i, mFinishQueue.size());
+ getInputChannelName().c_str(), i, mFinishQueue.size());
}
- return 1; // keep the callback, try again later
+ return KEEP_CALLBACK; // try again later
}
ALOGW("Failed to send finished signal on channel '%s'. status=%d",
getInputChannelName().c_str(), status);
if (status != DEAD_OBJECT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
- String8 message;
- message.appendFormat("Failed to finish input event. status=%d", status);
- jniThrowRuntimeException(env, message.string());
+ std::string message =
+ android::base::StringPrintf("Failed to finish input event. status=%d",
+ status);
+ jniThrowRuntimeException(env, message.c_str());
mMessageQueue->raiseAndClearException(env, "finishInputEvent");
}
- return 0; // remove the callback
+ return REMOVE_CALLBACK;
}
}
if (kDebugDispatchCycle) {
@@ -213,12 +234,12 @@ int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data)
}
mFinishQueue.clear();
setFdEvents(ALOOPER_EVENT_INPUT);
- return 1;
+ return KEEP_CALLBACK;
}
ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
"events=0x%x", getInputChannelName().c_str(), events);
- return 1;
+ return KEEP_CALLBACK;
}
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
@@ -354,6 +375,23 @@ status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
}
}
+std::string NativeInputEventReceiver::dump(const char* prefix) {
+ std::string out;
+ std::string consumerDump = addPrefix(mInputConsumer.dump(), " ");
+ out = out + "mInputConsumer:\n" + consumerDump + "\n";
+
+ out += android::base::StringPrintf("mBatchedInputEventPending: %s\n",
+ toString(mBatchedInputEventPending));
+ out = out + "mFinishQueue:\n";
+ for (const Finish& finish : mFinishQueue) {
+ out += android::base::StringPrintf(" seq=%" PRIu32 " handled=%s\n", finish.seq,
+ toString(finish.handled));
+ }
+ if (mFinishQueue.empty()) {
+ out = out + " <empty>\n";
+ }
+ return addPrefix(out, prefix);
+}
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
@@ -374,9 +412,10 @@ static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
receiverWeak, inputChannel, messageQueue);
status_t status = receiver->initialize();
if (status) {
- String8 message;
- message.appendFormat("Failed to initialize input event receiver. status=%d", status);
- jniThrowRuntimeException(env, message.string());
+ std::string message =
+ android::base::StringPrintf("Failed to initialize input event receiver. status=%d",
+ status);
+ jniThrowRuntimeException(env, message.c_str());
return 0;
}
@@ -397,9 +436,9 @@ static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jlong receiverPtr,
reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
status_t status = receiver->finishInputEvent(seq, handled);
if (status && status != DEAD_OBJECT) {
- String8 message;
- message.appendFormat("Failed to finish input event. status=%d", status);
- jniThrowRuntimeException(env, message.string());
+ std::string message =
+ android::base::StringPrintf("Failed to finish input event. status=%d", status);
+ jniThrowRuntimeException(env, message.c_str());
}
}
@@ -411,26 +450,31 @@ static jboolean nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jlong
status_t status = receiver->consumeEvents(env, true /*consumeBatches*/, frameTimeNanos,
&consumedBatch);
if (status && status != DEAD_OBJECT && !env->ExceptionCheck()) {
- String8 message;
- message.appendFormat("Failed to consume batched input event. status=%d", status);
- jniThrowRuntimeException(env, message.string());
+ std::string message =
+ android::base::StringPrintf("Failed to consume batched input event. status=%d",
+ status);
+ jniThrowRuntimeException(env, message.c_str());
return JNI_FALSE;
}
return consumedBatch ? JNI_TRUE : JNI_FALSE;
}
+static jstring nativeDump(JNIEnv* env, jclass clazz, jlong receiverPtr, jstring prefix) {
+ sp<NativeInputEventReceiver> receiver =
+ reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
+ ScopedUtfChars prefixChars(env, prefix);
+ return env->NewStringUTF(receiver->dump(prefixChars.c_str()).c_str());
+}
static const JNINativeMethod gMethods[] = {
- /* name, signature, funcPtr */
- { "nativeInit",
- "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J",
- (void*)nativeInit },
- { "nativeDispose", "(J)V",
- (void*)nativeDispose },
- { "nativeFinishInputEvent", "(JIZ)V",
- (void*)nativeFinishInputEvent },
- { "nativeConsumeBatchedInputEvents", "(JJ)Z",
- (void*)nativeConsumeBatchedInputEvents },
+ /* name, signature, funcPtr */
+ {"nativeInit",
+ "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J",
+ (void*)nativeInit},
+ {"nativeDispose", "(J)V", (void*)nativeDispose},
+ {"nativeFinishInputEvent", "(JIZ)V", (void*)nativeFinishInputEvent},
+ {"nativeConsumeBatchedInputEvents", "(JJ)Z", (void*)nativeConsumeBatchedInputEvents},
+ {"nativeDump", "(JLjava/lang/String;)Ljava/lang/String;", (void*)nativeDump},
};
int register_android_view_InputEventReceiver(JNIEnv* env) {
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 6eb89040998a..6212bcbbc05f 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2738,4 +2738,14 @@ enum PageId {
// CATEGORY: SETTINGS
// OS: S
SETTINGS_COLUMBUS = 1848;
+
+ // OPEN: Settings > Accessibility > Magnification > Settings > Magnification area > Magnification switch shortcut dialog
+ // CATEGORY: SETTINGS
+ // OS: S
+ DIALOG_MAGNIFICATION_SWITCH_SHORTCUT = 1849;
+
+ // OPEN: Settings > Network & internet > Adaptive connectivity
+ // CATEGORY: SETTINGS
+ // OS: R QPR
+ ADAPTIVE_CONNECTIVITY_CATEGORY = 1850;
}
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index d5619ca96fbd..9fccdaf9684f 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -507,7 +507,7 @@ message GlobalSettingsProto {
}
optional IntentFirewall intent_firewall = 65;
- optional SettingProto job_scheduler_constants = 66 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ reserved 66; // job_scheduler_constants
optional SettingProto job_scheduler_quota_controller_constants = 149 [ (android.privacy).dest = DEST_AUTOMATIC ];
reserved 150; // job_scheduler_time_controller_constants
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index 0455d58f498b..a2f2c46cba6a 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -174,6 +174,16 @@ message PowerManagerServiceDumpProto {
optional BatterySaverStateMachineProto battery_saver_state_machine = 50;
// Attentive timeout in ms. The timeout is disabled if it is set to -1.
optional sint32 attentive_timeout_ms = 51;
+ // The time (in the elapsed realtime timebase) at which the battery level will reach 0%. This
+ // is provided as an enhanced estimate and only valid if
+ // last_enhanced_discharge_time_updated_elapsed is greater than 0.
+ optional int64 enhanced_discharge_time_elapsed = 52;
+ // Timestamp (in the elapsed realtime timebase) of last update to enhanced battery estimate
+ // data.
+ optional int64 last_enhanced_discharge_time_updated_elapsed = 53;
+ // Whether or not the current enhanced discharge prediction is personalized based on device
+ // usage or not.
+ optional bool is_enhanced_discharge_prediction_personalized = 54;
}
// A com.android.server.power.PowerManagerService.SuspendBlockerImpl object.
diff --git a/core/res/Android.bp b/core/res/Android.bp
index b365de4f4630..f94a2b08e6c3 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -46,6 +46,13 @@ android_app {
},
}
+java_genrule {
+ name: "framework-res-package-jar",
+ srcs: [":framework-res{.export-package.apk}"],
+ out: ["framework-res-package.jar"],
+ cmd: "cp $(in) $(out)",
+}
+
// This logic can be removed once robolectric's transition to binary resources is complete
filegroup {
name: "robolectric_framework_raw_res_files",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 32c1e4a1411c..57c1fcf7bfb4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -102,6 +102,7 @@
<protected-broadcast android:name="android.os.action.POWER_SAVE_WHITELIST_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL" />
+ <protected-broadcast android:name="android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED" />
<!-- @deprecated This is rarely used and will be phased out soon. -->
<protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
@@ -5040,6 +5041,10 @@
<permission android:name="android.permission.RESET_APP_ERRORS"
android:protectionLevel="signature" />
+ <!-- @hide Allows an application to create/destroy input consumer. -->
+ <permission android:name="android.permission.INPUT_CONSUMER"
+ android:protectionLevel="signature" />
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 26dac618ee7e..b6f6627a5b8e 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -515,9 +515,9 @@
<string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"‏للسماح للتطبيق بتلقّي الحِزم التي يتم إرسالها إلى جميع الأجهزة على شبكة Wi-Fi باستخدام عناوين بث متعدد، وليس باستخدام جهاز Android TV فقط. ويؤدي ذلك إلى استخدام قدر أكبر من الطاقة يفوق ما يتم استهلاكه في وضع البث غير المتعدد."</string>
<string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"‏للسماح للتطبيق بتلقي الحزم التي يتم إرسالها إلى جميع الأجهزة على شبكة Wi-Fi باستخدام عناوين بث متعدد، وليس باستخدام هاتفك فقط. ويؤدي ذلك إلى استخدام قدر أكبر من الطاقة يفوق وضع البث غير المتعدد."</string>
<string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"الدخول إلى إعدادات بلوتوث"</string>
- <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"للسماح للتطبيق بتهيئة لوحة البلوتوث المحلي، واكتشاف أجهزة التحكم عن بعد والاقتران بها."</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"للسماح للتطبيق بإعداد لوحة البلوتوث المحلي، واكتشاف أجهزة التحكم عن بعد والاقتران بها."</string>
<string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"‏للسماح للتطبيق بضبط البلوتوث على جهاز Android TV واكتشاف الأجهزة البعيدة والاقتران بها."</string>
- <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"للسماح للتطبيق بتهيئة هاتف البلوتوث المحلي، واكتشاف أجهزة التحكم عن بعد والاقتران بها."</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"للسماح للتطبيق بإعداد هاتف البلوتوث المحلي، واكتشاف أجهزة التحكم عن بعد والاقتران بها."</string>
<string name="permlab_accessWimaxState" msgid="7029563339012437434">"‏الاتصال بـشبكة WiMAX وقطع الاتصال بها"</string>
<string name="permdesc_accessWimaxState" msgid="5372734776802067708">"‏للسماح للتطبيق بتحديد ما إذا تم تفعيل WiMAX وتحديد معلومات حول أي شبكات WiMAX متصلة."</string>
<string name="permlab_changeWimaxState" msgid="6223305780806267462">"‏تغيير حالة WiMAX"</string>
@@ -1412,7 +1412,7 @@
<string name="select_input_method" msgid="3971267998568587025">"اختيار أسلوب الإدخال"</string>
<string name="show_ime" msgid="6406112007347443383">"استمرار عرضها على الشاشة أثناء نشاط لوحة المفاتيح الفعلية"</string>
<string name="hardware" msgid="1800597768237606953">"إظهار لوحة المفاتيح الافتراضية"</string>
- <string name="select_keyboard_layout_notification_title" msgid="4427643867639774118">"تهيئة لوحة المفاتيح الفعلية"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="4427643867639774118">"إعداد لوحة المفاتيح الفعلية"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"انقر لاختيار لغة وتنسيق"</string>
<string name="fast_scroll_alphabet" msgid="8854435958703888376">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 085df65907f8..f9e3e2fa97e7 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -945,7 +945,7 @@
<string name="autofill_postal_code" msgid="7034789388968295591">"Kode pos"</string>
<string name="autofill_state" msgid="3341725337190434069">"Negara Bagian"</string>
<string name="autofill_zip_code" msgid="1315503730274962450">"Kode pos"</string>
- <string name="autofill_county" msgid="7781382735643492173">"Wilayah"</string>
+ <string name="autofill_county" msgid="7781382735643492173">"County"</string>
<string name="autofill_island" msgid="5367139008536593734">"Pulau"</string>
<string name="autofill_district" msgid="6428712062213557327">"Distrik"</string>
<string name="autofill_department" msgid="9047276226873531529">"Departemen"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 8871293c1b2f..df7781e089dd 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1773,7 +1773,7 @@
<string name="restr_pin_try_later" msgid="5897719962541636727">"Обиди се повторно подоцна"</string>
<string name="immersive_cling_title" msgid="2307034298721541791">"Се прикажува на цел екран"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"За да излезете, повлечете одозгора надолу."</string>
- <string name="immersive_cling_positive" msgid="7047498036346489883">"Разбрав"</string>
+ <string name="immersive_cling_positive" msgid="7047498036346489883">"Сфатив"</string>
<string name="done_label" msgid="7283767013231718521">"Готово"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Приказ на часови во кружно движење"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Приказ на минути во кружно движење"</string>
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 000e870369db..0a751dd7c66b 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -408,6 +408,9 @@ public class ActivityThreadTest {
int originalVirtualDisplayOrientation = virtualDisplayContext.getResources()
.getConfiguration().orientation;
+
+ // Perform global config change and verify there is no config change in derived display
+ // context.
Configuration newAppConfig = new Configuration(originalAppConfig);
newAppConfig.seq++;
newAppConfig.orientation = newAppConfig.orientation == ORIENTATION_PORTRAIT
@@ -417,7 +420,7 @@ public class ActivityThreadTest {
activityThread.handleConfigurationChanged(newAppConfig);
try {
- assertEquals("Virtual display orientation should not change when process"
+ assertEquals("Virtual display orientation must not change when process"
+ " configuration orientation changes.",
originalVirtualDisplayOrientation,
virtualDisplayContext.getResources().getConfiguration().orientation);
@@ -438,6 +441,50 @@ public class ActivityThreadTest {
}
@Test
+ public void testActivityOrientationChanged_DoesntOverrideVirtualDisplayOrientation() {
+ final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+ final ActivityThread activityThread = activity.getActivityThread();
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ Configuration originalActivityConfig =
+ new Configuration(activity.getResources().getConfiguration());
+ DisplayManager dm = activity.getSystemService(DisplayManager.class);
+
+ int virtualDisplayWidth;
+ int virtualDisplayHeight;
+ if (originalActivityConfig.orientation == ORIENTATION_PORTRAIT) {
+ virtualDisplayWidth = 100;
+ virtualDisplayHeight = 200;
+ } else {
+ virtualDisplayWidth = 200;
+ virtualDisplayHeight = 100;
+ }
+ Display virtualDisplay = dm.createVirtualDisplay("virtual-display",
+ virtualDisplayWidth, virtualDisplayHeight, 200, null, 0).getDisplay();
+ Context virtualDisplayContext = activity.createDisplayContext(virtualDisplay);
+ int originalVirtualDisplayOrientation = virtualDisplayContext.getResources()
+ .getConfiguration().orientation;
+
+ // Perform activity config change and verify there is no config change in derived
+ // display context.
+ Configuration newActivityConfig = new Configuration(originalActivityConfig);
+ newActivityConfig.seq++;
+ newActivityConfig.orientation = newActivityConfig.orientation == ORIENTATION_PORTRAIT
+ ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+
+ activityThread.updatePendingActivityConfiguration(activity.getActivityToken(),
+ newActivityConfig);
+ activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
+ newActivityConfig, INVALID_DISPLAY);
+
+ assertEquals("Virtual display orientation must not change when activity"
+ + " configuration orientation changes.",
+ originalVirtualDisplayOrientation,
+ virtualDisplayContext.getResources().getConfiguration().orientation);
+ });
+ }
+
+ @Test
public void testHandleConfigurationChanged_DoesntOverrideActivityConfig() {
final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index efcd458e19cc..45adf833de97 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -29,31 +29,50 @@ import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
+import java.util.HashMap;
+import java.util.Map;
+
public class ResourcesManagerTest extends TestCase {
+ private static final int SECONDARY_DISPLAY_ID = 1;
private static final String APP_ONE_RES_DIR = "app_one.apk";
private static final String APP_ONE_RES_SPLIT_DIR = "app_one_split.apk";
private static final String APP_TWO_RES_DIR = "app_two.apk";
private static final String LIB_RES_DIR = "lib.apk";
private ResourcesManager mResourcesManager;
- private DisplayMetrics mDisplayMetrics;
+ private Map<Integer, DisplayMetrics> mDisplayMetricsMap;
@Override
protected void setUp() throws Exception {
super.setUp();
- mDisplayMetrics = new DisplayMetrics();
- mDisplayMetrics.setToDefaults();
+ mDisplayMetricsMap = new HashMap<>();
+
+ DisplayMetrics defaultDisplayMetrics = new DisplayMetrics();
+ defaultDisplayMetrics.setToDefaults();
// Override defaults (which take device specific properties).
- mDisplayMetrics.density = 1.0f;
- mDisplayMetrics.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
- mDisplayMetrics.xdpi = DisplayMetrics.DENSITY_DEFAULT;
- mDisplayMetrics.ydpi = DisplayMetrics.DENSITY_DEFAULT;
- mDisplayMetrics.noncompatDensity = mDisplayMetrics.density;
- mDisplayMetrics.noncompatDensityDpi = mDisplayMetrics.densityDpi;
- mDisplayMetrics.noncompatXdpi = DisplayMetrics.DENSITY_DEFAULT;
- mDisplayMetrics.noncompatYdpi = DisplayMetrics.DENSITY_DEFAULT;
+ defaultDisplayMetrics.density = 1.0f;
+ defaultDisplayMetrics.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
+ defaultDisplayMetrics.xdpi = DisplayMetrics.DENSITY_DEFAULT;
+ defaultDisplayMetrics.ydpi = DisplayMetrics.DENSITY_DEFAULT;
+ defaultDisplayMetrics.widthPixels = 1440;
+ defaultDisplayMetrics.heightPixels = 2960;
+ defaultDisplayMetrics.noncompatDensity = defaultDisplayMetrics.density;
+ defaultDisplayMetrics.noncompatDensityDpi = defaultDisplayMetrics.densityDpi;
+ defaultDisplayMetrics.noncompatXdpi = DisplayMetrics.DENSITY_DEFAULT;
+ defaultDisplayMetrics.noncompatYdpi = DisplayMetrics.DENSITY_DEFAULT;
+ defaultDisplayMetrics.noncompatWidthPixels = defaultDisplayMetrics.widthPixels;
+ defaultDisplayMetrics.noncompatHeightPixels = defaultDisplayMetrics.heightPixels;
+ mDisplayMetricsMap.put(Display.DEFAULT_DISPLAY, defaultDisplayMetrics);
+
+ DisplayMetrics secondaryDisplayMetrics = new DisplayMetrics();
+ secondaryDisplayMetrics.setTo(defaultDisplayMetrics);
+ secondaryDisplayMetrics.widthPixels = 50;
+ secondaryDisplayMetrics.heightPixels = 100;
+ secondaryDisplayMetrics.noncompatWidthPixels = secondaryDisplayMetrics.widthPixels;
+ secondaryDisplayMetrics.noncompatHeightPixels = secondaryDisplayMetrics.heightPixels;
+ mDisplayMetricsMap.put(SECONDARY_DISPLAY_ID, secondaryDisplayMetrics);
mResourcesManager = new ResourcesManager() {
@Override
@@ -63,7 +82,7 @@ public class ResourcesManagerTest extends TestCase {
@Override
protected DisplayMetrics getDisplayMetrics(int displayId, DisplayAdjustments daj) {
- return mDisplayMetrics;
+ return mDisplayMetricsMap.get(displayId);
}
};
}
@@ -71,12 +90,12 @@ public class ResourcesManagerTest extends TestCase {
@SmallTest
public void testMultipleCallsWithIdenticalParametersCacheReference() {
Resources resources = mResourcesManager.getResources(
- null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ null, APP_ONE_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources);
Resources newResources = mResourcesManager.getResources(
- null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ null, APP_ONE_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(newResources);
assertSame(resources, newResources);
@@ -85,14 +104,14 @@ public class ResourcesManagerTest extends TestCase {
@SmallTest
public void testMultipleCallsWithDifferentParametersReturnDifferentReferences() {
Resources resources = mResourcesManager.getResources(
- null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ null, APP_ONE_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources);
Configuration overrideConfig = new Configuration();
overrideConfig.smallestScreenWidthDp = 200;
Resources newResources = mResourcesManager.getResources(
- null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, overrideConfig,
+ null, APP_ONE_RES_DIR, null, null, null, null, overrideConfig,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(newResources);
assertNotSame(resources, newResources);
@@ -101,13 +120,13 @@ public class ResourcesManagerTest extends TestCase {
@SmallTest
public void testAddingASplitCreatesANewImpl() {
Resources resources1 = mResourcesManager.getResources(
- null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ null, APP_ONE_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources1);
Resources resources2 = mResourcesManager.getResources(
null, APP_ONE_RES_DIR, new String[] { APP_ONE_RES_SPLIT_DIR }, null, null,
- Display.DEFAULT_DISPLAY, null, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO,null,
+ null, null, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null,
null);
assertNotNull(resources2);
@@ -118,12 +137,12 @@ public class ResourcesManagerTest extends TestCase {
@SmallTest
public void testUpdateConfigurationUpdatesAllAssetManagers() {
Resources resources1 = mResourcesManager.getResources(
- null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ null, APP_ONE_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources1);
Resources resources2 = mResourcesManager.getResources(
- null, APP_TWO_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ null, APP_TWO_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources2);
@@ -131,7 +150,7 @@ public class ResourcesManagerTest extends TestCase {
final Configuration overrideConfig = new Configuration();
overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
Resources resources3 = mResourcesManager.getResources(
- activity, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY,
+ activity, APP_ONE_RES_DIR, null, null, null, null,
overrideConfig, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources3);
@@ -152,7 +171,7 @@ public class ResourcesManagerTest extends TestCase {
final Configuration expectedConfig = new Configuration();
expectedConfig.setToDefaults();
expectedConfig.setLocales(LocaleList.getAdjustedDefault());
- expectedConfig.densityDpi = mDisplayMetrics.densityDpi;
+ expectedConfig.densityDpi = mDisplayMetricsMap.get(Display.DEFAULT_DISPLAY).densityDpi;
expectedConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
assertEquals(expectedConfig, resources1.getConfiguration());
@@ -164,13 +183,13 @@ public class ResourcesManagerTest extends TestCase {
public void testTwoActivitiesWithIdenticalParametersShareImpl() {
Binder activity1 = new Binder();
Resources resources1 = mResourcesManager.getResources(
- activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ activity1, APP_ONE_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources1);
Binder activity2 = new Binder();
Resources resources2 = mResourcesManager.getResources(
- activity2, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ activity2, APP_ONE_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources1);
@@ -201,7 +220,7 @@ public class ResourcesManagerTest extends TestCase {
final Configuration overrideConfig = new Configuration();
overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
mResourcesManager.updateResourcesForActivity(activity1, overrideConfig,
- Display.DEFAULT_DISPLAY, false /* movedToDifferentDisplay */);
+ Display.DEFAULT_DISPLAY);
assertSame(resources1, theme.getResources());
// Make sure we can still access the data.
@@ -226,7 +245,7 @@ public class ResourcesManagerTest extends TestCase {
Configuration config2 = new Configuration();
config2.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
Resources resources2 = mResourcesManager.getResources(
- activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config2,
+ activity1, APP_ONE_RES_DIR, null, null, null, null, config2,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources2);
@@ -250,8 +269,7 @@ public class ResourcesManagerTest extends TestCase {
// Now update the Activity base override, and both resources should update.
config1.orientation = Configuration.ORIENTATION_LANDSCAPE;
- mResourcesManager.updateResourcesForActivity(activity1, config1, Display.DEFAULT_DISPLAY,
- false /* movedToDifferentDisplay */);
+ mResourcesManager.updateResourcesForActivity(activity1, config1, Display.DEFAULT_DISPLAY);
expectedConfig1.orientation = Configuration.ORIENTATION_LANDSCAPE;
assertEquals(expectedConfig1, resources1.getConfiguration());
@@ -290,4 +308,41 @@ public class ResourcesManagerTest extends TestCase {
assertEquals(originalOverrideDensity,
resources.getDisplayAdjustments().getConfiguration().densityDpi);
}
+
+ @SmallTest
+ public void testChangingActivityDisplayDoesntOverrideDisplayRequestedByResources() {
+ Binder activity = new Binder();
+
+ // Create a base token resources that are based on the default display.
+ Resources activityResources = mResourcesManager.createBaseTokenResources(
+ activity, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
+ // Create another resources that explicitly override the display of the base token above
+ // and set it to DEFAULT_DISPLAY.
+ Resources defaultDisplayResources = mResourcesManager.getResources(
+ activity, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
+
+ assertEquals(mDisplayMetricsMap.get(Display.DEFAULT_DISPLAY).widthPixels,
+ activityResources.getDisplayMetrics().widthPixels);
+ assertEquals(mDisplayMetricsMap.get(Display.DEFAULT_DISPLAY).heightPixels,
+ activityResources.getDisplayMetrics().heightPixels);
+ assertEquals(mDisplayMetricsMap.get(Display.DEFAULT_DISPLAY).widthPixels,
+ defaultDisplayResources.getDisplayMetrics().widthPixels);
+ assertEquals(mDisplayMetricsMap.get(Display.DEFAULT_DISPLAY).widthPixels,
+ defaultDisplayResources.getDisplayMetrics().widthPixels);
+
+ // Now change the display of the activity and ensure the activity's display metrics match
+ // the new display, but the other resources remain based on the default display.
+ mResourcesManager.updateResourcesForActivity(activity, null, SECONDARY_DISPLAY_ID);
+
+ assertEquals(mDisplayMetricsMap.get(SECONDARY_DISPLAY_ID).widthPixels,
+ activityResources.getDisplayMetrics().widthPixels);
+ assertEquals(mDisplayMetricsMap.get(SECONDARY_DISPLAY_ID).heightPixels,
+ activityResources.getDisplayMetrics().heightPixels);
+ assertEquals(mDisplayMetricsMap.get(Display.DEFAULT_DISPLAY).widthPixels,
+ defaultDisplayResources.getDisplayMetrics().widthPixels);
+ assertEquals(mDisplayMetricsMap.get(Display.DEFAULT_DISPLAY).widthPixels,
+ defaultDisplayResources.getDisplayMetrics().widthPixels);
+ }
}
diff --git a/core/tests/coretests/src/android/text/OWNERS b/core/tests/coretests/src/android/text/OWNERS
index a35c6042bf53..0b51b2d90b79 100644
--- a/core/tests/coretests/src/android/text/OWNERS
+++ b/core/tests/coretests/src/android/text/OWNERS
@@ -1,5 +1,4 @@
set noparent
siyamed@google.com
-nona@google.com
-clarabayarri@google.com \ No newline at end of file
+nona@google.com \ No newline at end of file
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index af02b7bdbd90..de128ad6d78e 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -746,6 +746,20 @@ public class InsetsControllerTest {
mController.onControlsChanged(createSingletonControl(ITYPE_IME));
assertEquals(newState.getSource(ITYPE_IME),
mTestHost.getModifiedState().peekSource(ITYPE_IME));
+
+ // The modified frames cannot be updated if there is an animation.
+ mController.onControlsChanged(createSingletonControl(ITYPE_NAVIGATION_BAR));
+ mController.hide(navigationBars());
+ newState = new InsetsState(mController.getState(), true /* copySource */);
+ newState.getSource(ITYPE_NAVIGATION_BAR).getFrame().top--;
+ mController.onStateChanged(newState);
+ assertNotEquals(newState.getSource(ITYPE_NAVIGATION_BAR),
+ mTestHost.getModifiedState().peekSource(ITYPE_NAVIGATION_BAR));
+
+ // The modified frames can be updated while the animation is done.
+ mController.cancelExistingAnimations();
+ assertEquals(newState.getSource(ITYPE_NAVIGATION_BAR),
+ mTestHost.getModifiedState().peekSource(ITYPE_NAVIGATION_BAR));
});
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index 7807f019914e..bef27e2a2f63 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -39,6 +39,7 @@ import org.junit.runners.Suite;
BatteryStatsTimerTest.class,
BatteryStatsUidTest.class,
BatteryStatsUserLifecycleTests.class,
+ BstatsCpuTimesValidationTest.class,
KernelCpuProcStringReaderTest.class,
KernelCpuUidActiveTimeReaderTest.class,
KernelCpuUidBpfMapReaderTest.class,
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
index c577eeffd488..fe7c944ebd30 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
@@ -29,6 +29,8 @@ LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp
LOCAL_DEX_PREOPT := false
+LOCAL_EMMA_INSTRUMENT := false
+
mainDexList:= \
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
@@ -60,6 +62,8 @@ LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp2
LOCAL_DEX_PREOPT := false
+LOCAL_EMMA_INSTRUMENT := false
+
mainDexList2:= \
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
index da40940e92e9..3636c73ffc9c 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
@@ -33,6 +33,8 @@ LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
LOCAL_DEX_PREOPT := false
+LOCAL_EMMA_INSTRUMENT := false
+
include $(BUILD_PACKAGE)
$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
index 665e22d5a0bc..67f1fa574c07 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
@@ -28,6 +28,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
LOCAL_DEX_PREOPT := false
+LOCAL_EMMA_INSTRUMENT := false
+
mainDexList:= \
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
index c827fa80ebcd..33871e527820 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
@@ -28,6 +28,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
LOCAL_DEX_PREOPT := false
+LOCAL_EMMA_INSTRUMENT := false
+
mainDexList:= \
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
index 3d6ad7d1aa57..1b267ee93cce 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
@@ -31,6 +31,8 @@ mainDexList:= \
LOCAL_DEX_PREOPT := false
+LOCAL_EMMA_INSTRUMENT := false
+
LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
include $(BUILD_PACKAGE)
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index d0e688d3efc1..e122e0026aac 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -144,13 +144,6 @@ prebuilt_etc {
}
prebuilt_etc {
- name: "allowed_privapp_com.android.car.floatingcardslauncher",
- sub_dir: "permissions",
- src: "com.android.car.floatingcardslauncher.xml",
- filename_from_src: true,
-}
-
-prebuilt_etc {
name: "allowed_privapp_com.android.car.ui.paintbooth",
sub_dir: "permissions",
src: "com.android.car.ui.paintbooth.xml",
diff --git a/data/etc/car/com.android.car.floatingcardslauncher.xml b/data/etc/car/com.android.car.floatingcardslauncher.xml
deleted file mode 100644
index 2755fee4eb55..000000000000
--- a/data/etc/car/com.android.car.floatingcardslauncher.xml
+++ /dev/null
@@ -1,25 +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
- -->
-<permissions>
- <privapp-permissions package="com.android.car.floatingcardslauncher">
- <permission name="android.permission.ACTIVITY_EMBEDDING"/>
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- <permission name="android.permission.MANAGE_USERS"/>
- <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- </privapp-permissions>
-</permissions>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index f41049058a62..4f95a53e0ec8 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -684,15 +684,13 @@ public final class Bitmap implements Parcelable {
return b;
}
- // FIXME: The maxTargetSdk should be R, once R is no longer set to
- // CUR_DEVELOPMENT.
/**
* Creates a new immutable bitmap backed by ashmem which can efficiently
* be passed between processes.
*
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
publicAlternatives = "Use {@link #asShared()} instead")
public Bitmap createAshmemBitmap() {
checkRecycled("Can't copy a recycled bitmap");
diff --git a/graphics/java/android/graphics/BlurShader.java b/graphics/java/android/graphics/BlurShader.java
new file mode 100644
index 000000000000..779a89051060
--- /dev/null
+++ b/graphics/java/android/graphics/BlurShader.java
@@ -0,0 +1,65 @@
+/*
+ * 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 android.graphics;
+
+import android.annotation.Nullable;
+
+/**
+ * A subclass of shader that blurs input from another {@link android.graphics.Shader} instance
+ * or all the drawing commands with the {@link android.graphics.Paint} that this shader is
+ * attached to.
+ */
+public final class BlurShader extends Shader {
+
+ private final float mRadiusX;
+ private final float mRadiusY;
+ private final Shader mInputShader;
+
+ private long mNativeInputShader = 0;
+
+ /**
+ * Create a {@link BlurShader} that blurs the contents of the optional input shader
+ * with the specified radius along the x and y axis. If no input shader is provided
+ * then all drawing commands issued with a {@link android.graphics.Paint} that this
+ * shader is installed in will be blurred
+ * @param radiusX Radius of blur along the X axis
+ * @param radiusY Radius of blur along the Y axis
+ * @param inputShader Input shader that provides the content to be blurred
+ */
+ public BlurShader(float radiusX, float radiusY, @Nullable Shader inputShader) {
+ mRadiusX = radiusX;
+ mRadiusY = radiusY;
+ mInputShader = inputShader;
+ }
+
+ /** @hide **/
+ @Override
+ protected long createNativeInstance(long nativeMatrix) {
+ mNativeInputShader = mInputShader != null ? mInputShader.getNativeInstance() : 0;
+ return nativeCreate(nativeMatrix, mRadiusX, mRadiusY, mNativeInputShader);
+ }
+
+ /** @hide **/
+ @Override
+ protected boolean shouldDiscardNativeInstance() {
+ long currentNativeInstance = mInputShader != null ? mInputShader.getNativeInstance() : 0;
+ return mNativeInputShader != currentNativeInstance;
+ }
+
+ private static native long nativeCreate(long nativeMatrix, float radiusX, float radiusY,
+ long inputShader);
+}
diff --git a/keystore/TEST_MAPPING b/keystore/TEST_MAPPING
new file mode 100644
index 000000000000..0511967a229b
--- /dev/null
+++ b/keystore/TEST_MAPPING
@@ -0,0 +1,74 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsKeystoreTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.RequiresDevice"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.SignatureTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.RsaSignaturePerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.RsaKeyGenPerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.RsaCipherPerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.MacTest#testLargeMsgKat"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.KeyPairGeneratorTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.KeyGeneratorTest#testHmacKeySupportedSizes"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.HmacMacPerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.EcdsaSignaturePerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.EcKeyGenPerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.DesCipherPerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.CipherTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.AttestationPerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.AndroidKeyStoreTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.AesCipherPerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.AESCipherNistCavpKatTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.DESedeECBPKCS7PaddingCipherTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.DESedeECBNoPaddingCipherTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.DESedeECBPKCS7PaddingCipherTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsKeystoreTestCases"
+ }
+ ]
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
new file mode 100644
index 000000000000..126374829a18
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -0,0 +1,161 @@
+/*
+ * 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;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.window.TaskOrganizer;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Unified task organizer for all components in the shell.
+ */
+public class ShellTaskOrganizer extends TaskOrganizer {
+
+ private static final String TAG = "ShellTaskOrganizer";
+
+ /**
+ * Callbacks for when the tasks change in the system.
+ */
+ public interface TaskListener {
+ default void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {}
+ default void onTaskInfoChanged(RunningTaskInfo taskInfo) {}
+ default void onTaskVanished(RunningTaskInfo taskInfo) {}
+ default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {}
+ }
+
+ private final SparseArray<ArrayList<TaskListener>> mListenersByWindowingMode =
+ new SparseArray<>();
+
+ // Keeps track of all the tasks reported to this organizer (changes in windowing mode will
+ // require us to report to both old and new listeners)
+ private final SparseArray<Pair<RunningTaskInfo, SurfaceControl>> mTasks = new SparseArray<>();
+
+ /**
+ * Adds a listener for tasks in a specific windowing mode.
+ */
+ public void addListener(TaskListener listener, int... windowingModes) {
+ for (int winMode : windowingModes) {
+ ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(winMode);
+ if (listeners == null) {
+ listeners = new ArrayList<>();
+ mListenersByWindowingMode.put(winMode, listeners);
+ }
+ if (listeners.contains(listener)) {
+ Log.w(TAG, "Listener already exists");
+ return;
+ }
+ listeners.add(listener);
+
+ // Notify the listener of all existing tasks in that windowing mode
+ for (int i = mTasks.size() - 1; i >= 0; i--) {
+ Pair<RunningTaskInfo, SurfaceControl> data = mTasks.valueAt(i);
+ int taskWinMode = data.first.configuration.windowConfiguration.getWindowingMode();
+ if (taskWinMode == winMode) {
+ listener.onTaskAppeared(data.first, data.second);
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes a registered listener.
+ */
+ public void removeListener(TaskListener listener) {
+ for (int i = 0; i < mListenersByWindowingMode.size(); i++) {
+ mListenersByWindowingMode.valueAt(i).remove(listener);
+ }
+ }
+
+ @Override
+ public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
+ mTasks.put(taskInfo.taskId, new Pair<>(taskInfo, leash));
+ ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(
+ getWindowingMode(taskInfo));
+ if (listeners != null) {
+ for (int i = listeners.size() - 1; i >= 0; i--) {
+ listeners.get(i).onTaskAppeared(taskInfo, leash);
+ }
+ }
+ }
+
+ @Override
+ public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
+ Pair<RunningTaskInfo, SurfaceControl> data = mTasks.get(taskInfo.taskId);
+ int winMode = getWindowingMode(taskInfo);
+ int prevWinMode = getWindowingMode(data.first);
+ if (prevWinMode != -1 && prevWinMode != winMode) {
+ // TODO: We currently send vanished/appeared as the task moves between win modes, but
+ // we should consider adding a different mode-changed callback
+ ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(prevWinMode);
+ if (listeners != null) {
+ for (int i = listeners.size() - 1; i >= 0; i--) {
+ listeners.get(i).onTaskVanished(taskInfo);
+ }
+ }
+ listeners = mListenersByWindowingMode.get(winMode);
+ if (listeners != null) {
+ SurfaceControl leash = data.second;
+ for (int i = listeners.size() - 1; i >= 0; i--) {
+ listeners.get(i).onTaskAppeared(taskInfo, leash);
+ }
+ }
+ } else {
+ ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(winMode);
+ if (listeners != null) {
+ for (int i = listeners.size() - 1; i >= 0; i--) {
+ listeners.get(i).onTaskInfoChanged(taskInfo);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
+ ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(
+ getWindowingMode(taskInfo));
+ if (listeners != null) {
+ for (int i = listeners.size() - 1; i >= 0; i--) {
+ listeners.get(i).onBackPressedOnTaskRoot(taskInfo);
+ }
+ }
+ }
+
+ @Override
+ public void onTaskVanished(RunningTaskInfo taskInfo) {
+ int prevWinMode = getWindowingMode(mTasks.get(taskInfo.taskId).first);
+ mTasks.remove(taskInfo.taskId);
+ ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(prevWinMode);
+ if (listeners != null) {
+ for (int i = listeners.size() - 1; i >= 0; i--) {
+ listeners.get(i).onTaskVanished(taskInfo);
+ }
+ }
+ }
+
+ private int getWindowingMode(RunningTaskInfo taskInfo) {
+ return taskInfo.configuration.windowConfiguration.getWindowingMode();
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index aeda2d923490..283fd8d997c9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -68,7 +68,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
private final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
private final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>();
- protected DisplayImeController(IWindowManager wmService, DisplayController displayController,
+ public DisplayImeController(IWindowManager wmService, DisplayController displayController,
Handler mainHandler, TransactionPool transactionPool) {
mHandler = mainHandler;
mWmService = wmService;
@@ -76,7 +76,8 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
mDisplayController = displayController;
}
- protected void startMonitorDisplays() {
+ /** Starts monitor displays changes and set insets controller for each displays. */
+ public void startMonitorDisplays() {
mDisplayController.addDisplayWindowListener(this);
}
@@ -493,29 +494,4 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
return IInputMethodManager.Stub.asInterface(
ServiceManager.getService(Context.INPUT_METHOD_SERVICE));
}
-
- /** Builds {@link DisplayImeController} instance. */
- public static class Builder {
- private IWindowManager mWmService;
- private DisplayController mDisplayController;
- private Handler mHandler;
- private TransactionPool mTransactionPool;
-
- public Builder(IWindowManager wmService, DisplayController displayController,
- Handler handler, TransactionPool transactionPool) {
- mWmService = wmService;
- mDisplayController = displayController;
- mHandler = handler;
- mTransactionPool = transactionPool;
- }
-
- /** Builds and initializes {@link DisplayImeController} instance. */
- public DisplayImeController build() {
- DisplayImeController displayImeController = new DisplayImeController(mWmService,
- mDisplayController, mHandler, mTransactionPool);
- // Separates startMonitorDisplays from constructor to prevent circular init issue.
- displayImeController.startMonitorDisplays();
- return displayImeController;
- }
- }
}
diff --git a/libs/WindowManager/Shell/tests/README.md b/libs/WindowManager/Shell/tests/README.md
new file mode 100644
index 000000000000..c19db76a358c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/README.md
@@ -0,0 +1,15 @@
+# WM Shell Test
+
+This contains all tests written for WM (WindowManager) Shell and it's currently
+divided into 3 categories
+
+- unittest, tests against individual functions, usually @SmallTest and do not
+ require UI automation nor real device to run
+- integration, this maybe a mix of functional and integration tests. Contains
+ tests verify the WM Shell as a whole, like talking to WM core. This usually
+ involves mocking the window manager service or even talking to the real one.
+ Due to this nature, test cases in this package is normally annotated as
+ @LargeTest and runs with UI automation on real device
+- flicker, similar to functional tests with its sole focus on flickerness. See
+ [WM Shell Flicker Test Package](http://cs/android/framework/base/libs/WindowManager/Shell/tests/flicker/)
+ for more details
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
new file mode 100644
index 000000000000..587902221826
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -0,0 +1,34 @@
+//
+// 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.
+//
+
+android_test {
+ name: "WMShellFlickerTests",
+ srcs: ["src/**/*.java", "src/**/*.kt"],
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTest.xml",
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+ libs: ["android.test.runner"],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "flickerlib",
+ "truth-prebuilt",
+ "app-helpers-core",
+ "launcher-helper-lib",
+ "launcher-aosp-tapl"
+ ],
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
new file mode 100644
index 000000000000..8b2f6681554a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker">
+
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
+ <!-- Read and write traces from external storage -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <!-- Write secure settings -->
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <!-- Capture screen contents -->
+ <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
+ <!-- Enable / Disable tracing !-->
+ <uses-permission android:name="android.permission.DUMP" />
+ <!-- Run layers trace -->
+ <uses-permission android:name="android.permission.HARDWARE_TEST"/>
+ <!-- Workaround grant runtime permission exception from b/152733071 -->
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
+ <uses-permission android:name="android.permission.READ_LOGS"/>
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wm.shell.flicker"
+ android:label="WindowManager Shell Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
new file mode 100644
index 000000000000..526fc502c0fb
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright 2020 Google Inc. All Rights Reserved.
+ -->
+<configuration description="Runs WindowManager Shell Flicker Tests">
+ <option name="test-tag" value="FlickerTests" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on" />
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true" />
+ <!-- set WM tracing verbose level to all -->
+ <option name="run-command" value="cmd window tracing level all" />
+ <!-- inform WM to log all transactions -->
+ <option name="run-command" value="cmd window tracing transaction" />
+ <!-- restart launcher to activate TAPL -->
+ <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.DeviceCleaner">
+ <!-- reboot the device to teardown any crashed tests -->
+ <option name="cleanup-action" value="REBOOT" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="WMShellFlickerTests.apk"/>
+ <option name="test-file-name" value="WMShellFlickerTestApp.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.wm.shell.flicker"/>
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+ <option name="shell-timeout" value="6600s" />
+ <option name="test-timeout" value="6000s" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/storage/emulated/0/Android/data/com.android.wm.shell.flicker/files" />
+ <option name="collect-on-run-ended-only" value="true" />
+ <option name="clean-up" value="true" />
+ </metrics_collector>
+</configuration>
diff --git a/libs/WindowManager/Shell/tests/flicker/README.md b/libs/WindowManager/Shell/tests/flicker/README.md
new file mode 100644
index 000000000000..4502d498a65b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/README.md
@@ -0,0 +1,10 @@
+# WM Shell Flicker Test Package
+
+Please reference the following links
+
+- [Introduction to Flicker Test Library](http://cs/android/platform_testing/libraries/flicker/)
+- [Flicker Test in frameworks/base](http://cs/android/frameworks/base/tests/FlickerTests/)
+
+on what is Flicker Test and how to write a Flicker Test
+
+To run the Flicker Tests for WM Shell, simply run `atest WMShellFlickerTests`
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
new file mode 100644
index 000000000000..4ff2bfca3a4a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -0,0 +1,153 @@
+/*
+ * 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 com.android.server.wm.flicker.dsl.EventLogAssertion
+import com.android.server.wm.flicker.dsl.LayersAssertion
+import com.android.server.wm.flicker.dsl.WmAssertion
+import com.android.server.wm.flicker.helpers.WindowUtils
+
+@JvmOverloads
+fun WmAssertion.statusBarWindowIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("statusBarWindowIsAlwaysVisible", enabled, bugId) {
+ this.showsAboveAppWindow(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun WmAssertion.navBarWindowIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("navBarWindowIsAlwaysVisible", enabled, bugId) {
+ this.showsAboveAppWindow(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.noUncoveredRegions(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ allStates: Boolean = true,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
+ val endingBounds = WindowUtils.getDisplayBounds(endRotation)
+ if (allStates) {
+ all("noUncoveredRegions", enabled, 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 LayersAssertion.navBarLayerIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("navBarLayerIsAlwaysVisible", enabled, bugId) {
+ this.showsLayer(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.statusBarLayerIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("statusBarLayerIsAlwaysVisible", enabled, bugId) {
+ this.showsLayer(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.navBarLayerRotatesAndScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
+ val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
+
+ start("navBarLayerRotatesAndScales_StartingPos", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
+ }
+ end("navBarLayerRotatesAndScales_EndingPost", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, endingPos)
+ }
+
+ if (startingPos == endingPos) {
+ all("navBarLayerRotatesAndScales", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
+ }
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.statusBarLayerRotatesScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
+ val endingPos = WindowUtils.getStatusBarPosition(endRotation)
+
+ start("statusBarLayerRotatesScales_StartingPos", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, startingPos)
+ }
+ end("statusBarLayerRotatesScales_EndingPos", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, endingPos)
+ }
+}
+
+fun EventLogAssertion.focusChanges(
+ vararg windows: String,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all(enabled = enabled, bugId = bugId) {
+ this.focusChanges(windows)
+ }
+}
+
+fun EventLogAssertion.focusDoesNotChange(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all(enabled = enabled, bugId = bugId) {
+ this.focusDoesNotChange()
+ }
+}
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
new file mode 100644
index 000000000000..99f824bb8341
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt
@@ -0,0 +1,130 @@
+/*
+ * 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.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
+
+/**
+ * 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)
+ }
+
+ /**
+ * 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 {
+ const val NAVIGATION_BAR_WINDOW_TITLE = "NavigationBar"
+ const val STATUS_BAR_WINDOW_TITLE = "StatusBar"
+ const val DOCKED_STACK_DIVIDER = "DockedStackDivider"
+ }
+}
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
new file mode 100644
index 000000000000..90334ae91e9d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NonRotationTestBase.kt
@@ -0,0 +1,36 @@
+/*
+ * 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/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManager.java b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt
index 90187a298cf2..308a36efef87 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManager.java
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt
@@ -14,31 +14,18 @@
* limitations under the License.
*/
-package com.android.systemui.onehanded;
+package com.android.wm.shell.flicker.helpers
-/**
- * The base class of OneHandedManager
- */
-public interface OneHandedManager {
-
- /**
- * Set one handed enabled or disabled
- */
- default void setOneHandedEnabled(boolean enabled) {}
-
- /**
- * Set task stack changed to exit
- */
- default void setTaskChangeToExit(boolean enabled) {}
-
- /**
- * Exit one handed mode
- */
- default void stopOneHanded() {}
-
- /**
- * Trigger one handed mode
- */
- default void startOneHanded() {}
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import com.android.server.wm.flicker.StandardAppHelper
+abstract class FlickerAppHelper(
+ instr: Instrumentation,
+ launcherName: String,
+ launcherStrategy: ILauncherStrategy
+) : StandardAppHelper(instr, sFlickerPackage, launcherName, launcherStrategy) {
+ companion object {
+ var sFlickerPackage = "com.android.wm.shell.flicker.testapp"
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
new file mode 100644
index 000000000000..539170202b8a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import com.android.server.wm.flicker.helpers.hasPipWindow
+import com.android.server.wm.flicker.helpers.closePipWindow
+import org.junit.Assert
+
+class PipAppHelper(
+ instr: Instrumentation,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : FlickerAppHelper(instr, "PipApp", launcherStrategy) {
+ fun clickEnterPipButton(device: UiDevice) {
+ val enterPipButton = device.findObject(By.res(getPackage(), "enter_pip"))
+ Assert.assertNotNull("Pip button not found, this usually happens when the device " +
+ "was left in an unknown state (e.g. in split screen)", enterPipButton)
+ enterPipButton.click()
+ device.hasPipWindow()
+ }
+
+ fun closePipWindow(device: UiDevice) {
+ device.closePipWindow()
+ }
+}
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
new file mode 100644
index 000000000000..4b04449bdbc2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -0,0 +1,121 @@
+/*
+ * 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.view.Surface
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.helpers.closePipWindow
+import com.android.server.wm.flicker.helpers.expandPipWindow
+import com.android.server.wm.flicker.helpers.hasPipWindow
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
+import com.android.wm.shell.flicker.navBarLayerRotatesAndScales
+import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.noUncoveredRegions
+import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
+import com.android.wm.shell.flicker.statusBarLayerRotatesScales
+import com.android.wm.shell.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
+
+/**
+ * Test Pip launch.
+ * To run this test: `atest FlickerTests:PipToAppTest`
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 152738416)
+class EnterPipTest(
+ rotationName: String,
+ rotation: Int
+) : PipTestBase(rotationName, rotation) {
+ @Test
+ fun test() {
+ flicker(instrumentation) {
+ withTag { buildTestTag("enterPip", testApp, rotation) }
+ repeat { 1 }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ device.pressHome()
+ testApp.open()
+ this.setRotation(rotation)
+ }
+ }
+ teardown {
+ eachRun {
+ if (device.hasPipWindow()) {
+ device.closePipWindow()
+ }
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ test {
+ if (device.hasPipWindow()) {
+ device.closePipWindow()
+ }
+ }
+ }
+ transitions {
+ testApp.clickEnterPipButton(device)
+ device.expandPipWindow()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ all("pipWindowBecomesVisible") {
+ this.showsAppWindow(testApp.`package`)
+ .then()
+ .showsAppWindow(sPipWindowTitle)
+ }
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
+ navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0)
+ statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
+
+ all("pipLayerBecomesVisible") {
+ this.showsLayer(testApp.launcherName)
+ .then()
+ .showsLayer(sPipWindowTitle)
+ }
+ }
+ }
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val supportedRotations = intArrayOf(Surface.ROTATION_0)
+ return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/dagger/OneHandedModule.java b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
index fe5fa2b5fccd..3822d69a65f5 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/dagger/OneHandedModule.java
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
@@ -14,23 +14,18 @@
* limitations under the License.
*/
-package com.android.systemui.onehanded.dagger;
+package com.android.wm.shell.flicker.pip
-import com.android.systemui.onehanded.OneHandedManager;
-import com.android.systemui.onehanded.OneHandedManagerImpl;
+import com.android.wm.shell.flicker.NonRotationTestBase
+import com.android.wm.shell.flicker.helpers.PipAppHelper
-import dagger.Binds;
-import dagger.Module;
-
-/**
- * Dagger Module for One handed.
- */
-@Module
-public abstract class OneHandedModule {
-
- /** Binds OneHandedManager as the default. */
- @Binds
- public abstract OneHandedManager provideOneHandedManager(
- OneHandedManagerImpl oneHandedManagerImpl);
+abstract class PipTestBase(
+ rotationName: String,
+ rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
+ protected val testApp = PipAppHelper(instrumentation)
+ companion object {
+ const val sPipWindowTitle = "PipMenuActivity"
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/Android.bp b/libs/WindowManager/Shell/tests/flicker/test-apps/Android.bp
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/Android.bp
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp
new file mode 100644
index 000000000000..d12b49245277
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp
@@ -0,0 +1,20 @@
+// 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.
+
+android_test {
+ name: "WMShellFlickerTestApp",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+ test_suites: ["device-tests"],
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
new file mode 100644
index 000000000000..95dc1d48eee8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker.testapp">
+
+ <uses-sdk android:minSdkVersion="29"
+ android:targetSdkVersion="29"/>
+ <application android:allowBackup="false"
+ android:supportsRtl="true">
+ <activity android:name=".PipActivity"
+ android:resizeableActivity="true"
+ android:supportsPictureInPicture="true"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
+ android:taskAffinity="com.android.wm.shell.flicker.testapp.PipActivity"
+ android:label="PipApp"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
new file mode 100644
index 000000000000..e1870d9c523d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/holo_blue_bright">
+ <Button android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/enter_pip"
+ android:text="Enter PIP"/>
+</LinearLayout>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
new file mode 100644
index 000000000000..305281691e11
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
@@ -0,0 +1,45 @@
+/*
+ * 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.testapp;
+
+import android.app.Activity;
+import android.app.PictureInPictureParams;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.util.Rational;
+import android.view.WindowManager;
+import android.widget.Button;
+
+public class PipActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ WindowManager.LayoutParams p = getWindow().getAttributes();
+ p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
+ .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ getWindow().setAttributes(p);
+ setContentView(R.layout.activity_pip);
+ Button enterPip = (Button) findViewById(R.id.enter_pip);
+
+ PictureInPictureParams params = new PictureInPictureParams.Builder()
+ .setAspectRatio(new Rational(1, 1))
+ .setSourceRectHint(new Rect(0, 0, 100, 100))
+ .build();
+
+ enterPip.setOnClickListener((v) -> enterPictureInPictureMode(params));
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp
index 9868879cebb9..692e2fa88fc3 100644
--- a/libs/WindowManager/Shell/tests/Android.bp
+++ b/libs/WindowManager/Shell/tests/unittest/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
android_test {
- name: "WindowManagerShellTests",
+ name: "WMShellUnitTests",
srcs: ["**/*.java"],
diff --git a/libs/WindowManager/Shell/tests/AndroidManifest.xml b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
index a8f795ec8a8d..a8f795ec8a8d 100644
--- a/libs/WindowManager/Shell/tests/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
diff --git a/libs/WindowManager/Shell/tests/AndroidTest.xml b/libs/WindowManager/Shell/tests/unittest/AndroidTest.xml
index 4dce4db360e4..21ed2c075dff 100644
--- a/libs/WindowManager/Shell/tests/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/unittest/AndroidTest.xml
@@ -17,12 +17,12 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="install-arg" value="-t" />
- <option name="test-file-name" value="WindowManagerShellTests.apk" />
+ <option name="test-file-name" value="WMShellUnitTests.apk" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="framework-base-presubmit" />
- <option name="test-tag" value="WindowManagerShellTests" />
+ <option name="test-tag" value="WMShellUnitTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.wm.shell.tests" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
diff --git a/libs/WindowManager/Shell/tests/res/values/config.xml b/libs/WindowManager/Shell/tests/unittest/res/values/config.xml
index c894eb0133b5..c894eb0133b5 100644
--- a/libs/WindowManager/Shell/tests/res/values/config.xml
+++ b/libs/WindowManager/Shell/tests/unittest/res/values/config.xml
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
new file mode 100644
index 000000000000..10672c8d87ad
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -0,0 +1,121 @@
+/*
+ * 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;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+
+import static org.junit.Assert.assertTrue;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.content.res.Configuration;
+import android.view.SurfaceControl;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+/**
+ * Tests for the shell task organizer.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ShellTaskOrganizerTests {
+
+ ShellTaskOrganizer mOrganizer;
+
+ private class TrackingTaskListener implements ShellTaskOrganizer.TaskListener {
+ final ArrayList<RunningTaskInfo> appeared = new ArrayList<>();
+ final ArrayList<RunningTaskInfo> vanished = new ArrayList<>();
+ final ArrayList<RunningTaskInfo> infoChanged = new ArrayList<>();
+
+ @Override
+ public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
+ appeared.add(taskInfo);
+ }
+
+ @Override
+ public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
+ infoChanged.add(taskInfo);
+ }
+
+ @Override
+ public void onTaskVanished(RunningTaskInfo taskInfo) {
+ vanished.add(taskInfo);
+ }
+
+ @Override
+ public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
+ // Not currently used
+ }
+ }
+
+ @Before
+ public void setUp() {
+ mOrganizer = new ShellTaskOrganizer();
+ }
+
+ @Test
+ public void testAppearedVanished() {
+ RunningTaskInfo taskInfo = createTaskInfo(WINDOWING_MODE_MULTI_WINDOW);
+ TrackingTaskListener listener = new TrackingTaskListener();
+ mOrganizer.addListener(listener, WINDOWING_MODE_MULTI_WINDOW);
+ mOrganizer.onTaskAppeared(taskInfo, null);
+ assertTrue(listener.appeared.contains(taskInfo));
+
+ mOrganizer.onTaskVanished(taskInfo);
+ assertTrue(listener.vanished.contains(taskInfo));
+ }
+
+ @Test
+ public void testAddListenerExistingTasks() {
+ RunningTaskInfo taskInfo = createTaskInfo(WINDOWING_MODE_MULTI_WINDOW);
+ mOrganizer.onTaskAppeared(taskInfo, null);
+
+ TrackingTaskListener listener = new TrackingTaskListener();
+ mOrganizer.addListener(listener, WINDOWING_MODE_MULTI_WINDOW);
+ assertTrue(listener.appeared.contains(taskInfo));
+ }
+
+ @Test
+ public void testWindowingModeChange() {
+ RunningTaskInfo taskInfo = createTaskInfo(WINDOWING_MODE_MULTI_WINDOW);
+ TrackingTaskListener mwListener = new TrackingTaskListener();
+ TrackingTaskListener pipListener = new TrackingTaskListener();
+ mOrganizer.addListener(mwListener, WINDOWING_MODE_MULTI_WINDOW);
+ mOrganizer.addListener(pipListener, WINDOWING_MODE_PINNED);
+ mOrganizer.onTaskAppeared(taskInfo, null);
+ assertTrue(mwListener.appeared.contains(taskInfo));
+ assertTrue(pipListener.appeared.isEmpty());
+
+ taskInfo = createTaskInfo(WINDOWING_MODE_PINNED);
+ mOrganizer.onTaskInfoChanged(taskInfo);
+ assertTrue(mwListener.vanished.contains(taskInfo));
+ assertTrue(pipListener.appeared.contains(taskInfo));
+ }
+
+ private RunningTaskInfo createTaskInfo(int windowingMode) {
+ RunningTaskInfo taskInfo = new RunningTaskInfo();
+ taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
+ return taskInfo;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/common/DisplayLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java
index 2b5b77e49e3a..2b5b77e49e3a 100644
--- a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/common/DisplayLayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 4d7e5dfea4f7..dfb4009b07e2 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -37,7 +37,6 @@
#include <androidfw/TypeWrappers.h>
#include <cutils/atomic.h>
#include <utils/ByteOrder.h>
-#include <utils/Debug.h>
#include <utils/Log.h>
#include <utils/String16.h>
#include <utils/String8.h>
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 0b13754271b9..90d2537d97a8 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -464,6 +464,7 @@ cc_defaults {
"RootRenderNode.cpp",
"shader/Shader.cpp",
"shader/BitmapShader.cpp",
+ "shader/BlurShader.cpp",
"shader/ComposeShader.cpp",
"shader/LinearGradientShader.cpp",
"shader/RadialGradientShader.cpp",
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 87244427a719..ab9b8b55a4cb 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -56,12 +56,6 @@ class AHBUploader : public RefBase {
public:
virtual ~AHBUploader() {}
- // Called to start creation of the Vulkan and EGL contexts on another thread before we actually
- // need to do an upload.
- void initialize() {
- onInitialize();
- }
-
void destroy() {
std::lock_guard _lock{mLock};
LOG_ALWAYS_FATAL_IF(mPendingUploads, "terminate called while uploads in progress");
@@ -91,7 +85,6 @@ protected:
sp<ThreadBase> mUploadThread = nullptr;
private:
- virtual void onInitialize() = 0;
virtual void onIdle() = 0;
virtual void onDestroy() = 0;
@@ -141,7 +134,6 @@ private:
class EGLUploader : public AHBUploader {
private:
- void onInitialize() override {}
void onDestroy() override {
mEglManager.destroy();
}
@@ -231,62 +223,67 @@ private:
class VkUploader : public AHBUploader {
private:
- void onInitialize() override {
- std::lock_guard _lock{mLock};
- if (!mUploadThread) {
- mUploadThread = new ThreadBase{};
- }
- if (!mUploadThread->isRunning()) {
- mUploadThread->start("GrallocUploadThread");
- }
-
- mUploadThread->queue().post([this]() {
- std::lock_guard _lock{mVkLock};
- if (!mVulkanManager.hasVkContext()) {
- mVulkanManager.initialize();
- }
- });
- }
void onDestroy() override {
+ std::lock_guard _lock{mVkLock};
mGrContext.reset();
- mVulkanManager.destroy();
+ mVulkanManagerStrong.clear();
}
void onIdle() override {
- mGrContext.reset();
+ onDestroy();
}
- void onBeginUpload() override {
- {
- std::lock_guard _lock{mVkLock};
- if (!mVulkanManager.hasVkContext()) {
- LOG_ALWAYS_FATAL_IF(mGrContext,
- "GrContext exists with no VulkanManager for vulkan uploads");
- mUploadThread->queue().runSync([this]() {
- mVulkanManager.initialize();
- });
- }
- }
- if (!mGrContext) {
- GrContextOptions options;
- mGrContext = mVulkanManager.createContext(options);
- LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
- this->postIdleTimeoutCheck();
- }
- }
+ void onBeginUpload() override {}
bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
AHardwareBuffer* ahb) override {
- ATRACE_CALL();
+ bool uploadSucceeded = false;
+ mUploadThread->queue().runSync([this, &uploadSucceeded, bitmap, ahb]() {
+ ATRACE_CALL();
+ std::lock_guard _lock{mVkLock};
+
+ renderthread::VulkanManager* vkManager = getVulkanManager();
+ if (!vkManager->hasVkContext()) {
+ LOG_ALWAYS_FATAL_IF(mGrContext,
+ "GrContext exists with no VulkanManager for vulkan uploads");
+ vkManager->initialize();
+ }
+
+ if (!mGrContext) {
+ GrContextOptions options;
+ mGrContext = vkManager->createContext(options,
+ renderthread::VulkanManager::ContextType::kUploadThread);
+ LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
+ this->postIdleTimeoutCheck();
+ }
+
+ sk_sp<SkImage> image =
+ SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(), ahb);
+ mGrContext->submit(true);
+
+ uploadSucceeded = (image.get() != nullptr);
+ });
+ return uploadSucceeded;
+ }
- std::lock_guard _lock{mLock};
+ /* must be called on the upload thread after the vkLock has been acquired */
+ renderthread::VulkanManager* getVulkanManager() {
+ if (!mVulkanManagerStrong) {
+ mVulkanManagerStrong = mVulkanManagerWeak.promote();
+
+ // create a new manager if we couldn't promote the weak ref
+ if (!mVulkanManagerStrong) {
+ mVulkanManagerStrong = renderthread::VulkanManager::getInstance();
+ mGrContext.reset();
+ mVulkanManagerWeak = mVulkanManagerStrong;
+ }
+ }
- sk_sp<SkImage> image =
- SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(), ahb);
- return (image.get() != nullptr);
+ return mVulkanManagerStrong.get();
}
sk_sp<GrDirectContext> mGrContext;
- renderthread::VulkanManager mVulkanManager;
+ sp<renderthread::VulkanManager> mVulkanManagerStrong;
+ wp<renderthread::VulkanManager> mVulkanManagerWeak;
std::mutex mVkLock;
};
@@ -428,7 +425,6 @@ void HardwareBitmapUploader::initialize() {
bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
uirenderer::RenderPipelineType::SkiaGL;
createUploader(usingGL);
- sUploader->initialize();
}
void HardwareBitmapUploader::terminate() {
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 892d43a763a9..473dc53dc4bf 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -524,6 +524,7 @@ void* DisplayListData::push(size_t pod, Args&&... args) {
// Next greater multiple of SKLITEDL_PAGE.
fReserved = (fUsed + skip + SKLITEDL_PAGE) & ~(SKLITEDL_PAGE - 1);
fBytes.realloc(fReserved);
+ LOG_ALWAYS_FATAL_IF(fBytes.get() == nullptr, "realloc(%zd) failed", fReserved);
}
SkASSERT(fUsed + skip <= fReserved);
auto op = (T*)(fBytes.get() + fUsed);
diff --git a/libs/hwui/jni/Picture.cpp b/libs/hwui/jni/Picture.cpp
index d1b952130e88..8e4203c0b115 100644
--- a/libs/hwui/jni/Picture.cpp
+++ b/libs/hwui/jni/Picture.cpp
@@ -111,7 +111,7 @@ sk_sp<SkPicture> Picture::makePartialCopy() const {
SkPictureRecorder reRecorder;
- SkCanvas* canvas = reRecorder.beginRecording(mWidth, mHeight, NULL, 0);
+ SkCanvas* canvas = reRecorder.beginRecording(mWidth, mHeight);
mRecorder->partialReplay(canvas);
return reRecorder.finishRecordingAsPicture();
}
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 9b1972ed664f..7cb77233846f 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -7,6 +7,7 @@
#include "include/effects/SkRuntimeEffect.h"
#include "shader/Shader.h"
#include "shader/BitmapShader.h"
+#include "shader/BlurShader.h"
#include "shader/ComposeShader.h"
#include "shader/LinearGradientShader.h"
#include "shader/RadialGradientShader.h"
@@ -222,6 +223,22 @@ static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
///////////////////////////////////////////////////////////////////////////////////////////////
+static jlong BlurShader_create(JNIEnv* env , jobject o, jlong matrixPtr, jfloat sigmaX,
+ jfloat sigmaY, jlong shaderHandle) {
+ auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ auto* inputShader = reinterpret_cast<Shader*>(shaderHandle);
+
+ auto* blurShader = new BlurShader(
+ sigmaX,
+ sigmaY,
+ inputShader,
+ matrix
+ );
+ return reinterpret_cast<jlong>(blurShader);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlong matrixPtr,
jbyteArray inputs, jlong colorSpaceHandle, jboolean isOpaque) {
auto* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory);
@@ -273,6 +290,10 @@ static const JNINativeMethod gBitmapShaderMethods[] = {
{ "nativeCreate", "(JJII)J", (void*)BitmapShader_constructor },
};
+static const JNINativeMethod gBlurShaderMethods[] = {
+ { "nativeCreate", "(JFFJ)J", (void*)BlurShader_create }
+};
+
static const JNINativeMethod gLinearGradientMethods[] = {
{ "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
};
@@ -304,6 +325,8 @@ int register_android_graphics_Shader(JNIEnv* env)
NELEM(gShaderMethods));
android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
NELEM(gBitmapShaderMethods));
+ android::RegisterMethodsOrDie(env, "android/graphics/BlurShader", gBlurShaderMethods,
+ NELEM(gBlurShaderMethods));
android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
NELEM(gLinearGradientMethods));
android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index fc594da19708..e817ca744c58 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -184,7 +184,9 @@ static void android_view_ThreadedRenderer_setSurface(JNIEnv* env, jobject clazz,
proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
}
proxy->setSurface(window, enableTimeout);
- ANativeWindow_release(window);
+ if (window) {
+ ANativeWindow_release(window);
+ }
}
static jboolean android_view_ThreadedRenderer_pause(JNIEnv* env, jobject clazz,
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index aad0cca80cdc..b51f6dcfc66f 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -77,10 +77,10 @@ void RenderProxy::setName(const char* name) {
}
void RenderProxy::setSurface(ANativeWindow* window, bool enableTimeout) {
- ANativeWindow_acquire(window);
+ if (window) { ANativeWindow_acquire(window); }
mRenderThread.queue().post([this, win = window, enableTimeout]() mutable {
mContext->setSurface(win, enableTimeout);
- ANativeWindow_release(win);
+ if (win) { ANativeWindow_release(win); }
});
}
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 565fb61c8994..4dcbc4458e97 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -131,8 +131,7 @@ RenderThread::RenderThread()
, mFrameCallbackTaskPending(false)
, mRenderState(nullptr)
, mEglManager(nullptr)
- , mFunctorManager(WebViewFunctorManager::instance())
- , mVkManager(nullptr) {
+ , mFunctorManager(WebViewFunctorManager::instance()) {
Properties::load();
start("RenderThread");
}
@@ -166,7 +165,7 @@ void RenderThread::initThreadLocals() {
initializeChoreographer();
mEglManager = new EglManager();
mRenderState = new RenderState(*this);
- mVkManager = new VulkanManager();
+ mVkManager = VulkanManager::getInstance();
mCacheManager = new CacheManager();
}
@@ -196,7 +195,8 @@ void RenderThread::requireGlContext() {
}
void RenderThread::requireVkContext() {
- if (mVkManager->hasVkContext()) {
+ // the getter creates the context in the event it had been destroyed by destroyRenderingContext
+ if (vulkanManager().hasVkContext()) {
return;
}
mVkManager->initialize();
@@ -222,11 +222,16 @@ void RenderThread::destroyRenderingContext() {
mEglManager->destroy();
}
} else {
- if (vulkanManager().hasVkContext()) {
- setGrContext(nullptr);
- vulkanManager().destroy();
- }
+ setGrContext(nullptr);
+ mVkManager.clear();
+ }
+}
+
+VulkanManager& RenderThread::vulkanManager() {
+ if (!mVkManager.get()) {
+ mVkManager = VulkanManager::getInstance();
}
+ return *mVkManager.get();
}
void RenderThread::dumpGraphicsMemory(int fd) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index b8ce55650516..d7dc00b8a5c1 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -110,7 +110,7 @@ public:
void setGrContext(sk_sp<GrDirectContext> cxt);
CacheManager& cacheManager() { return *mCacheManager; }
- VulkanManager& vulkanManager() { return *mVkManager; }
+ VulkanManager& vulkanManager();
sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& skBitmap);
void dumpGraphicsMemory(int fd);
@@ -188,7 +188,7 @@ private:
sk_sp<GrDirectContext> mGrContext;
CacheManager* mCacheManager;
- VulkanManager* mVkManager;
+ sp<VulkanManager> mVkManager;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 249936eb485e..76ec078ce3c9 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -57,12 +57,22 @@ static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& fe
#define GET_INST_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(mInstance, "vk" #F)
#define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(mDevice, "vk" #F)
-void VulkanManager::destroy() {
- if (VK_NULL_HANDLE != mCommandPool) {
- mDestroyCommandPool(mDevice, mCommandPool, nullptr);
- mCommandPool = VK_NULL_HANDLE;
+sp<VulkanManager> VulkanManager::getInstance() {
+ // cache a weakptr to the context to enable a second thread to share the same vulkan state
+ static wp<VulkanManager> sWeakInstance = nullptr;
+ static std::mutex sLock;
+
+ std::lock_guard _lock{sLock};
+ sp<VulkanManager> vulkanManager = sWeakInstance.promote();
+ if (!vulkanManager.get()) {
+ vulkanManager = new VulkanManager();
+ sWeakInstance = vulkanManager;
}
+ return vulkanManager;
+}
+
+VulkanManager::~VulkanManager() {
if (mDevice != VK_NULL_HANDLE) {
mDeviceWaitIdle(mDevice);
mDestroyDevice(mDevice, nullptr);
@@ -73,6 +83,7 @@ void VulkanManager::destroy() {
}
mGraphicsQueue = VK_NULL_HANDLE;
+ mAHBUploadQueue = VK_NULL_HANDLE;
mPresentQueue = VK_NULL_HANDLE;
mDevice = VK_NULL_HANDLE;
mPhysicalDevice = VK_NULL_HANDLE;
@@ -175,6 +186,7 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
for (uint32_t i = 0; i < queueCount; i++) {
if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
mGraphicsQueueIndex = i;
+ LOG_ALWAYS_FATAL_IF(queueProps[i].queueCount < 2);
break;
}
}
@@ -283,7 +295,7 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
queueNextPtr, // pNext
0, // VkDeviceQueueCreateFlags
mGraphicsQueueIndex, // queueFamilyIndex
- 1, // queueCount
+ 2, // queueCount
queuePriorities, // pQueuePriorities
},
{
@@ -347,20 +359,7 @@ void VulkanManager::initialize() {
this->setupDevice(mExtensions, mPhysicalDeviceFeatures2);
mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
-
- // create the command pool for the command buffers
- if (VK_NULL_HANDLE == mCommandPool) {
- VkCommandPoolCreateInfo commandPoolInfo;
- memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
- commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- // this needs to be on the render queue
- commandPoolInfo.queueFamilyIndex = mGraphicsQueueIndex;
- commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
- SkDEBUGCODE(VkResult res =)
- mCreateCommandPool(mDevice, &commandPoolInfo, nullptr, &mCommandPool);
- SkASSERT(VK_SUCCESS == res);
- }
- LOG_ALWAYS_FATAL_IF(mCommandPool == VK_NULL_HANDLE);
+ mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 1, &mAHBUploadQueue);
mGetDeviceQueue(mDevice, mPresentQueueIndex, 0, &mPresentQueue);
@@ -369,7 +368,8 @@ void VulkanManager::initialize() {
}
}
-sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& options) {
+sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& options,
+ ContextType contextType) {
auto getProc = [](const char* proc_name, VkInstance instance, VkDevice device) {
if (device != VK_NULL_HANDLE) {
return vkGetDeviceProcAddr(device, proc_name);
@@ -381,7 +381,8 @@ sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& opti
backendContext.fInstance = mInstance;
backendContext.fPhysicalDevice = mPhysicalDevice;
backendContext.fDevice = mDevice;
- backendContext.fQueue = mGraphicsQueue;
+ backendContext.fQueue = (contextType == ContextType::kRenderThread) ? mGraphicsQueue
+ : mAHBUploadQueue;
backendContext.fGraphicsQueueIndex = mGraphicsQueueIndex;
backendContext.fMaxAPIVersion = mAPIVersion;
backendContext.fVkExtensions = &mExtensions;
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 3f2df8d75d89..75c05b828e5d 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -43,10 +43,9 @@ class RenderThread;
// This class contains the shared global Vulkan objects, such as VkInstance, VkDevice and VkQueue,
// which are re-used by CanvasContext. This class is created once and should be used by all vulkan
// windowing contexts. The VulkanManager must be initialized before use.
-class VulkanManager {
+class VulkanManager final : public RefBase {
public:
- explicit VulkanManager() {}
- ~VulkanManager() { destroy(); }
+ static sp<VulkanManager> getInstance();
// Sets up the vulkan context that is shared amonst all clients of the VulkanManager. This must
// be call once before use of the VulkanManager. Multiple calls after the first will simiply
@@ -68,9 +67,6 @@ public:
Frame dequeueNextBuffer(VulkanSurface* surface);
void swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect);
- // Cleans up all the global state in the VulkanManger.
- void destroy();
-
// Inserts a wait on fence command into the Vulkan command buffer.
status_t fenceWait(int fence, GrDirectContext* grContext);
@@ -83,12 +79,24 @@ public:
// the internal state of VulkanManager: VulkanManager must be alive to use the returned value.
VkFunctorInitParams getVkFunctorInitParams() const;
- sk_sp<GrDirectContext> createContext(const GrContextOptions& options);
+
+ enum class ContextType {
+ kRenderThread,
+ kUploadThread
+ };
+
+ // returns a Skia graphic context used to draw content on the specified thread
+ sk_sp<GrDirectContext> createContext(const GrContextOptions& options,
+ ContextType contextType = ContextType::kRenderThread);
uint32_t getDriverVersion() const { return mDriverVersion; }
private:
friend class VulkanSurface;
+
+ explicit VulkanManager() {}
+ ~VulkanManager();
+
// Sets up the VkInstance and VkDevice objects. Also fills out the passed in
// VkPhysicalDeviceFeatures struct.
void setupDevice(GrVkExtensions&, VkPhysicalDeviceFeatures2&);
@@ -154,9 +162,9 @@ private:
uint32_t mGraphicsQueueIndex;
VkQueue mGraphicsQueue = VK_NULL_HANDLE;
+ VkQueue mAHBUploadQueue = VK_NULL_HANDLE;
uint32_t mPresentQueueIndex;
VkQueue mPresentQueue = VK_NULL_HANDLE;
- VkCommandPool mCommandPool = VK_NULL_HANDLE;
// Variables saved to populate VkFunctorInitParams.
static const uint32_t mAPIVersion = VK_MAKE_VERSION(1, 1, 0);
diff --git a/libs/hwui/shader/BlurShader.cpp b/libs/hwui/shader/BlurShader.cpp
new file mode 100644
index 000000000000..4d18cdd27e4e
--- /dev/null
+++ b/libs/hwui/shader/BlurShader.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#include "BlurShader.h"
+#include "SkImageFilters.h"
+#include "SkRefCnt.h"
+#include "utils/Blur.h"
+
+namespace android::uirenderer {
+BlurShader::BlurShader(float radiusX, float radiusY, Shader* inputShader, const SkMatrix* matrix)
+ : Shader(matrix)
+ , skImageFilter(
+ SkImageFilters::Blur(
+ Blur::convertRadiusToSigma(radiusX),
+ Blur::convertRadiusToSigma(radiusY),
+ inputShader ? inputShader->asSkImageFilter() : nullptr)
+ ) { }
+
+sk_sp<SkImageFilter> BlurShader::makeSkImageFilter() {
+ return skImageFilter;
+}
+
+BlurShader::~BlurShader() {}
+
+} // namespace android::uirenderer \ No newline at end of file
diff --git a/libs/hwui/shader/BlurShader.h b/libs/hwui/shader/BlurShader.h
new file mode 100644
index 000000000000..9eb22bd11f4a
--- /dev/null
+++ b/libs/hwui/shader/BlurShader.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#pragma once
+#include "Shader.h"
+
+namespace android::uirenderer {
+
+/**
+ * Shader implementation that blurs another Shader instance or the source bitmap
+ */
+class BlurShader : public Shader {
+public:
+ /**
+ * Creates a BlurShader instance with the provided radius values to blur along the x and y
+ * axis accordingly.
+ *
+ * This will blur the contents of the provided input shader if it is non-null, otherwise
+ * the source bitmap will be blurred instead.
+ */
+ BlurShader(float radiusX, float radiusY, Shader* inputShader, const SkMatrix* matrix);
+ ~BlurShader() override;
+protected:
+ sk_sp<SkImageFilter> makeSkImageFilter() override;
+private:
+ sk_sp<SkImageFilter> skImageFilter;
+};
+
+} // namespace android::uirenderer \ No newline at end of file
diff --git a/libs/hwui/shader/Shader.h b/libs/hwui/shader/Shader.h
index 3c0cdaae8253..6403e1147ded 100644
--- a/libs/hwui/shader/Shader.h
+++ b/libs/hwui/shader/Shader.h
@@ -32,7 +32,9 @@ namespace android::uirenderer {
class Shader: public SkRefCnt {
public:
/**
- * Creates a Shader instance with an optional transformation matrix
+ * Creates a Shader instance with an optional transformation matrix. The transformation matrix
+ * is copied internally and ownership is unchanged. It is the responsibility of the caller to
+ * deallocate it appropriately.
* @param matrix Optional matrix to transform the underlying SkShader or SkImageFilter
*/
Shader(const SkMatrix* matrix);
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index fcc64fdd0be6..f77ca2a8c06c 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -73,7 +73,7 @@ TEST(SkiaCanvas, colorSpaceXform) {
// Test picture recording.
SkPictureRecorder recorder;
- SkCanvas* skPicCanvas = recorder.beginRecording(1, 1, NULL, 0);
+ SkCanvas* skPicCanvas = recorder.beginRecording(1, 1);
SkiaCanvas picCanvas(skPicCanvas);
picCanvas.drawBitmap(*adobeBitmap, 0, 0, nullptr);
sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
@@ -104,7 +104,7 @@ TEST(SkiaCanvas, captureCanvasState) {
// Create a picture canvas.
SkPictureRecorder recorder;
- SkCanvas* skPicCanvas = recorder.beginRecording(1, 1, NULL, 0);
+ SkCanvas* skPicCanvas = recorder.beginRecording(1, 1);
SkiaCanvas picCanvas(skPicCanvas);
state = picCanvas.captureCanvasState();
diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp
index 80b555be97dd..45da008c3e8e 100644
--- a/libs/input/MouseCursorController.cpp
+++ b/libs/input/MouseCursorController.cpp
@@ -168,7 +168,7 @@ void MouseCursorController::fade(PointerControllerInterface::Transition transiti
updatePointerLocked();
} else {
mLocked.pointerFadeDirection = -1;
- mContext.startAnimation();
+ startAnimationLocked();
}
}
@@ -185,7 +185,7 @@ void MouseCursorController::unfade(PointerControllerInterface::Transition transi
updatePointerLocked();
} else {
mLocked.pointerFadeDirection = 1;
- mContext.startAnimation();
+ startAnimationLocked();
}
}
@@ -312,10 +312,9 @@ void MouseCursorController::setCustomPointerIcon(const SpriteIcon& icon) {
updatePointerLocked();
}
-bool MouseCursorController::doFadingAnimation(nsecs_t timestamp, bool keepAnimating) {
+bool MouseCursorController::doFadingAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) {
nsecs_t frameDelay = timestamp - mContext.getAnimationTime();
-
- std::scoped_lock lock(mLock);
+ bool keepAnimating = false;
// Animate pointer fade.
if (mLocked.pointerFadeDirection < 0) {
@@ -337,13 +336,10 @@ bool MouseCursorController::doFadingAnimation(nsecs_t timestamp, bool keepAnimat
}
updatePointerLocked();
}
-
return keepAnimating;
}
-bool MouseCursorController::doBitmapAnimation(nsecs_t timestamp) {
- std::scoped_lock lock(mLock);
-
+bool MouseCursorController::doBitmapAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) {
std::map<int32_t, PointerAnimation>::const_iterator iter =
mLocked.animationResources.find(mLocked.requestedPointerType);
if (iter == mLocked.animationResources.end()) {
@@ -364,7 +360,6 @@ bool MouseCursorController::doBitmapAnimation(nsecs_t timestamp) {
spriteController->closeTransaction();
}
-
// Keep animating.
return true;
}
@@ -399,7 +394,7 @@ void MouseCursorController::updatePointerLocked() REQUIRES(mLock) {
if (anim_iter != mLocked.animationResources.end()) {
mLocked.animationFrameIndex = 0;
mLocked.lastFrameUpdatedTime = systemTime(SYSTEM_TIME_MONOTONIC);
- mContext.startAnimation();
+ startAnimationLocked();
}
mLocked.pointerSprite->setIcon(iter->second);
} else {
@@ -457,4 +452,38 @@ bool MouseCursorController::resourcesLoaded() {
return mLocked.resourcesLoaded;
}
+bool MouseCursorController::doAnimations(nsecs_t timestamp) {
+ std::scoped_lock lock(mLock);
+ bool keepFading = doFadingAnimationLocked(timestamp);
+ bool keepBitmap = doBitmapAnimationLocked(timestamp);
+ bool keepAnimating = keepFading || keepBitmap;
+ if (!keepAnimating) {
+ /*
+ * We know that this callback will be removed before another
+ * is added. mLock in PointerAnimator will not be released
+ * until after this is removed, and adding another callback
+ * requires that lock. Thus it's safe to set mLocked.animating
+ * here.
+ */
+ mLocked.animating = false;
+ }
+ return keepAnimating;
+}
+
+void MouseCursorController::startAnimationLocked() REQUIRES(mLock) {
+ using namespace std::placeholders;
+
+ if (mLocked.animating) {
+ return;
+ }
+ mLocked.animating = true;
+
+ std::function<bool(nsecs_t)> func = std::bind(&MouseCursorController::doAnimations, this, _1);
+ /*
+ * Using -1 for displayId here to avoid removing the callback
+ * if a TouchSpotController with the same display is removed.
+ */
+ mContext.addAnimationCallback(-1, func);
+}
+
} // namespace android
diff --git a/libs/input/MouseCursorController.h b/libs/input/MouseCursorController.h
index 448165b5ac46..e6dfc4c6f99a 100644
--- a/libs/input/MouseCursorController.h
+++ b/libs/input/MouseCursorController.h
@@ -25,6 +25,7 @@
#include <utils/Looper.h>
#include <utils/RefBase.h>
+#include <functional>
#include <map>
#include <memory>
#include <vector>
@@ -61,8 +62,7 @@ public:
void getAdditionalMouseResources();
bool isViewportValid();
- bool doBitmapAnimation(nsecs_t timestamp);
- bool doFadingAnimation(nsecs_t timestamp, bool keepAnimating);
+ bool doAnimations(nsecs_t timestamp);
bool resourcesLoaded();
@@ -96,6 +96,8 @@ private:
int32_t buttonState;
+ bool animating{false};
+
} mLocked GUARDED_BY(mLock);
bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
@@ -104,6 +106,11 @@ private:
void updatePointerLocked();
void loadResourcesLocked(bool getAdditionalMouseResources);
+
+ bool doBitmapAnimationLocked(nsecs_t timestamp);
+ bool doFadingAnimationLocked(nsecs_t timestamp);
+
+ void startAnimationLocked();
};
} // namespace android
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 14c96cefd462..8f04cfb70469 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -57,7 +57,6 @@ std::shared_ptr<PointerController> PointerController::create(
controller->mContext.setHandlerController(controller);
controller->mContext.setCallbackController(controller);
- controller->mContext.initializeDisplayEventReceiver();
return controller;
}
@@ -189,24 +188,6 @@ void PointerController::setCustomPointerIcon(const SpriteIcon& icon) {
mCursorController.setCustomPointerIcon(icon);
}
-void PointerController::doAnimate(nsecs_t timestamp) {
- std::scoped_lock lock(mLock);
-
- mContext.setAnimationPending(false);
-
- bool keepFading = false;
- keepFading = mCursorController.doFadingAnimation(timestamp, keepFading);
-
- for (auto& [displayID, spotController] : mLocked.spotControllers) {
- keepFading = spotController.doFadingAnimation(timestamp, keepFading);
- }
-
- bool keepBitmapFlipping = mCursorController.doBitmapAnimation(timestamp);
- if (keepFading || keepBitmapFlipping) {
- mContext.startAnimation();
- }
-}
-
void PointerController::doInactivityTimeout() {
fade(Transition::GRADUAL);
}
@@ -221,6 +202,11 @@ void PointerController::onDisplayViewportsUpdated(std::vector<DisplayViewport>&
for (auto it = mLocked.spotControllers.begin(); it != mLocked.spotControllers.end();) {
int32_t displayID = it->first;
if (!displayIdSet.count(displayID)) {
+ /*
+ * Ensures that an in-progress animation won't dereference
+ * a null pointer to TouchSpotController.
+ */
+ mContext.removeAnimationCallback(displayID);
it = mLocked.spotControllers.erase(it);
} else {
++it;
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 1f561da333b1..827fcf1e1bc1 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -70,7 +70,6 @@ public:
void setCustomPointerIcon(const SpriteIcon& icon);
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
void doInactivityTimeout();
- void doAnimate(nsecs_t timestamp);
void reloadPointerResources();
void onDisplayViewportsUpdated(std::vector<DisplayViewport>& viewports);
diff --git a/libs/input/PointerControllerContext.cpp b/libs/input/PointerControllerContext.cpp
index 2d7e22b01112..f30e8d8e33a5 100644
--- a/libs/input/PointerControllerContext.cpp
+++ b/libs/input/PointerControllerContext.cpp
@@ -38,10 +38,10 @@ PointerControllerContext::PointerControllerContext(
mSpriteController(spriteController),
mHandler(new MessageHandler()),
mCallback(new LooperCallback()),
- mController(controller) {
+ mController(controller),
+ mAnimator(*this) {
std::scoped_lock lock(mLock);
mLocked.inactivityTimeout = InactivityTimeout::NORMAL;
- mLocked.animationPending = false;
}
PointerControllerContext::~PointerControllerContext() {
@@ -57,15 +57,6 @@ void PointerControllerContext::setInactivityTimeout(InactivityTimeout inactivity
}
}
-void PointerControllerContext::startAnimation() {
- std::scoped_lock lock(mLock);
- if (!mLocked.animationPending) {
- mLocked.animationPending = true;
- mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
- mDisplayEventReceiver.requestNextVsync();
- }
-}
-
void PointerControllerContext::resetInactivityTimeout() {
std::scoped_lock lock(mLock);
resetInactivityTimeoutLocked();
@@ -85,14 +76,8 @@ void PointerControllerContext::removeInactivityTimeout() {
mLooper->removeMessages(mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT);
}
-void PointerControllerContext::setAnimationPending(bool animationPending) {
- std::scoped_lock lock(mLock);
- mLocked.animationPending = animationPending;
-}
-
-nsecs_t PointerControllerContext::getAnimationTime() {
- std::scoped_lock lock(mLock);
- return mLocked.animationTime;
+nsecs_t PointerControllerContext::getAnimationTime() REQUIRES(mAnimator.mLock) {
+ return mAnimator.getAnimationTimeLocked();
}
void PointerControllerContext::setHandlerController(std::shared_ptr<PointerController> controller) {
@@ -112,31 +97,8 @@ sp<SpriteController> PointerControllerContext::getSpriteController() {
return mSpriteController;
}
-void PointerControllerContext::initializeDisplayEventReceiver() {
- if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
- mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK, Looper::EVENT_INPUT,
- mCallback, nullptr);
- } else {
- ALOGE("Failed to initialize DisplayEventReceiver.");
- }
-}
-
void PointerControllerContext::handleDisplayEvents() {
- bool gotVsync = false;
- ssize_t n;
- nsecs_t timestamp;
- DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
- while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
- for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
- if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
- timestamp = buf[i].header.timestamp;
- gotVsync = true;
- }
- }
- }
- if (gotVsync) {
- mController.doAnimate(timestamp);
- }
+ mAnimator.handleVsyncEvents();
}
void PointerControllerContext::MessageHandler::handleMessage(const Message& message) {
@@ -176,4 +138,91 @@ int PointerControllerContext::LooperCallback::handleEvent(int /* fd */, int even
return 1; // keep the callback
}
+void PointerControllerContext::addAnimationCallback(int32_t displayId,
+ std::function<bool(nsecs_t)> callback) {
+ mAnimator.addCallback(displayId, callback);
+}
+
+void PointerControllerContext::removeAnimationCallback(int32_t displayId) {
+ mAnimator.removeCallback(displayId);
+}
+
+PointerControllerContext::PointerAnimator::PointerAnimator(PointerControllerContext& context)
+ : mContext(context) {
+ initializeDisplayEventReceiver();
+}
+
+void PointerControllerContext::PointerAnimator::initializeDisplayEventReceiver() {
+ if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
+ mContext.mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
+ Looper::EVENT_INPUT, mContext.mCallback, nullptr);
+ } else {
+ ALOGE("Failed to initialize DisplayEventReceiver.");
+ }
+}
+
+void PointerControllerContext::PointerAnimator::addCallback(int32_t displayId,
+ std::function<bool(nsecs_t)> callback) {
+ std::scoped_lock lock(mLock);
+ mLocked.callbacks[displayId] = callback;
+ startAnimationLocked();
+}
+
+void PointerControllerContext::PointerAnimator::removeCallback(int32_t displayId) {
+ std::scoped_lock lock(mLock);
+ auto it = mLocked.callbacks.find(displayId);
+ if (it == mLocked.callbacks.end()) {
+ return;
+ }
+ mLocked.callbacks.erase(it);
+}
+
+void PointerControllerContext::PointerAnimator::handleVsyncEvents() {
+ bool gotVsync = false;
+ ssize_t n;
+ nsecs_t timestamp;
+ DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
+ while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
+ for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
+ if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+ timestamp = buf[i].header.timestamp;
+ gotVsync = true;
+ }
+ }
+ }
+ if (gotVsync) {
+ std::scoped_lock lock(mLock);
+ mLocked.animationPending = false;
+ handleCallbacksLocked(timestamp);
+ }
+}
+
+nsecs_t PointerControllerContext::PointerAnimator::getAnimationTimeLocked() REQUIRES(mLock) {
+ return mLocked.animationTime;
+}
+
+void PointerControllerContext::PointerAnimator::startAnimationLocked() REQUIRES(mLock) {
+ if (!mLocked.animationPending) {
+ mLocked.animationPending = true;
+ mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ mDisplayEventReceiver.requestNextVsync();
+ }
+}
+
+void PointerControllerContext::PointerAnimator::handleCallbacksLocked(nsecs_t timestamp)
+ REQUIRES(mLock) {
+ for (auto it = mLocked.callbacks.begin(); it != mLocked.callbacks.end();) {
+ bool keepCallback = it->second(timestamp);
+ if (!keepCallback) {
+ it = mLocked.callbacks.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ if (!mLocked.callbacks.empty()) {
+ startAnimationLocked();
+ }
+}
+
} // namespace android
diff --git a/libs/input/PointerControllerContext.h b/libs/input/PointerControllerContext.h
index 92e1bda25f56..98073fea323e 100644
--- a/libs/input/PointerControllerContext.h
+++ b/libs/input/PointerControllerContext.h
@@ -26,6 +26,7 @@
#include <utils/Looper.h>
#include <utils/RefBase.h>
+#include <functional>
#include <map>
#include <memory>
#include <vector>
@@ -35,6 +36,8 @@
namespace android {
class PointerController;
+class MouseCursorController;
+class TouchSpotController;
/*
* Pointer resources.
@@ -96,7 +99,6 @@ public:
void startAnimation();
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
- void setAnimationPending(bool animationPending);
nsecs_t getAnimationTime();
void clearSpotsByDisplay(int32_t displayId);
@@ -107,9 +109,11 @@ public:
sp<PointerControllerPolicyInterface> getPolicy();
sp<SpriteController> getSpriteController();
- void initializeDisplayEventReceiver();
void handleDisplayEvents();
+ void addAnimationCallback(int32_t displayId, std::function<bool(nsecs_t)> callback);
+ void removeAnimationCallback(int32_t displayId);
+
class MessageHandler : public virtual android::MessageHandler {
public:
enum {
@@ -127,22 +131,47 @@ public:
};
private:
+ class PointerAnimator {
+ public:
+ PointerAnimator(PointerControllerContext& context);
+
+ void addCallback(int32_t displayId, std::function<bool(nsecs_t)> callback);
+ void removeCallback(int32_t displayId);
+ void handleVsyncEvents();
+ nsecs_t getAnimationTimeLocked();
+
+ mutable std::mutex mLock;
+
+ private:
+ struct Locked {
+ bool animationPending{false};
+ nsecs_t animationTime{systemTime(SYSTEM_TIME_MONOTONIC)};
+
+ std::unordered_map<int32_t, std::function<bool(nsecs_t)>> callbacks;
+ } mLocked GUARDED_BY(mLock);
+
+ DisplayEventReceiver mDisplayEventReceiver;
+
+ PointerControllerContext& mContext;
+
+ void initializeDisplayEventReceiver();
+ void startAnimationLocked();
+ void handleCallbacksLocked(nsecs_t timestamp);
+ };
+
sp<PointerControllerPolicyInterface> mPolicy;
sp<Looper> mLooper;
sp<SpriteController> mSpriteController;
sp<MessageHandler> mHandler;
sp<LooperCallback> mCallback;
- DisplayEventReceiver mDisplayEventReceiver;
-
PointerController& mController;
+ PointerAnimator mAnimator;
+
mutable std::mutex mLock;
struct Locked {
- bool animationPending;
- nsecs_t animationTime;
-
InactivityTimeout inactivityTimeout;
} mLocked GUARDED_BY(mLock);
diff --git a/libs/input/TouchSpotController.cpp b/libs/input/TouchSpotController.cpp
index c7430ceead41..f7c685ff8ba6 100644
--- a/libs/input/TouchSpotController.cpp
+++ b/libs/input/TouchSpotController.cpp
@@ -142,7 +142,8 @@ TouchSpotController::Spot* TouchSpotController::getSpot(uint32_t id,
}
TouchSpotController::Spot* TouchSpotController::createAndAddSpotLocked(uint32_t id,
- std::vector<Spot*>& spots) {
+ std::vector<Spot*>& spots)
+ REQUIRES(mLock) {
// Remove spots until we have fewer than MAX_SPOTS remaining.
while (spots.size() >= MAX_SPOTS) {
Spot* spot = removeFirstFadingSpotLocked(spots);
@@ -186,14 +187,13 @@ void TouchSpotController::releaseSpotLocked(Spot* spot) REQUIRES(mLock) {
if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
mLocked.recycledSprites.push_back(spot->sprite);
}
-
delete spot;
}
void TouchSpotController::fadeOutAndReleaseSpotLocked(Spot* spot) REQUIRES(mLock) {
if (spot->id != Spot::INVALID_ID) {
spot->id = Spot::INVALID_ID;
- mContext.startAnimation();
+ startAnimationLocked();
}
}
@@ -209,8 +209,24 @@ void TouchSpotController::reloadSpotResources() {
mContext.getPolicy()->loadPointerResources(&mResources, mDisplayId);
}
-bool TouchSpotController::doFadingAnimation(nsecs_t timestamp, bool keepAnimating) {
+bool TouchSpotController::doAnimations(nsecs_t timestamp) {
std::scoped_lock lock(mLock);
+ bool keepAnimating = doFadingAnimationLocked(timestamp);
+ if (!keepAnimating) {
+ /*
+ * We know that this callback will be removed before another
+ * is added. mLock in PointerAnimator will not be released
+ * until after this is removed, and adding another callback
+ * requires that lock. Thus it's safe to set mLocked.animating
+ * here.
+ */
+ mLocked.animating = false;
+ }
+ return keepAnimating;
+}
+
+bool TouchSpotController::doFadingAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) {
+ bool keepAnimating = false;
nsecs_t animationTime = mContext.getAnimationTime();
nsecs_t frameDelay = timestamp - animationTime;
size_t numSpots = mLocked.displaySpots.size();
@@ -233,4 +249,16 @@ bool TouchSpotController::doFadingAnimation(nsecs_t timestamp, bool keepAnimatin
return keepAnimating;
}
+void TouchSpotController::startAnimationLocked() REQUIRES(mLock) {
+ using namespace std::placeholders;
+
+ if (mLocked.animating) {
+ return;
+ }
+ mLocked.animating = true;
+
+ std::function<bool(nsecs_t)> func = std::bind(&TouchSpotController::doAnimations, this, _1);
+ mContext.addAnimationCallback(mDisplayId, func);
+}
+
} // namespace android
diff --git a/libs/input/TouchSpotController.h b/libs/input/TouchSpotController.h
index f3b355010bee..703de3603f48 100644
--- a/libs/input/TouchSpotController.h
+++ b/libs/input/TouchSpotController.h
@@ -17,6 +17,8 @@
#ifndef _UI_TOUCH_SPOT_CONTROLLER_H
#define _UI_TOUCH_SPOT_CONTROLLER_H
+#include <functional>
+
#include "PointerControllerContext.h"
namespace android {
@@ -34,7 +36,7 @@ public:
void clearSpots();
void reloadSpotResources();
- bool doFadingAnimation(nsecs_t timestamp, bool keepAnimating);
+ bool doAnimations(nsecs_t timestamp);
private:
struct Spot {
@@ -76,6 +78,8 @@ private:
std::vector<Spot*> displaySpots;
std::vector<sp<Sprite>> recycledSprites;
+ bool animating{false};
+
} mLocked GUARDED_BY(mLock);
Spot* getSpot(uint32_t id, const std::vector<Spot*>& spots);
@@ -84,6 +88,8 @@ private:
void releaseSpotLocked(Spot* spot);
void fadeOutAndReleaseSpotLocked(Spot* spot);
void fadeOutAndReleaseAllSpotsLocked();
+ bool doFadingAnimationLocked(nsecs_t timestamp);
+ void startAnimationLocked();
};
} // namespace android
diff --git a/location/java/android/location/timezone/LocationTimeZoneEvent.java b/location/java/android/location/timezone/LocationTimeZoneEvent.java
index ea3353c245e5..540bdfffe16a 100644
--- a/location/java/android/location/timezone/LocationTimeZoneEvent.java
+++ b/location/java/android/location/timezone/LocationTimeZoneEvent.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import java.util.ArrayList;
import java.util.Collections;
@@ -37,7 +38,7 @@ public final class LocationTimeZoneEvent implements Parcelable {
@IntDef({ EVENT_TYPE_UNKNOWN, EVENT_TYPE_SUCCESS, EVENT_TYPE_SUCCESS })
@interface EventType {}
- /** Uninitialized value for {@link #mEventType} */
+ /** Uninitialized value for {@link #mEventType} - must not be used for real events. */
private static final int EVENT_TYPE_UNKNOWN = 0;
/**
@@ -60,6 +61,9 @@ public final class LocationTimeZoneEvent implements Parcelable {
private static final int EVENT_TYPE_MAX = EVENT_TYPE_UNCERTAIN;
+ @NonNull
+ private final UserHandle mUserHandle;
+
@EventType
private final int mEventType;
@@ -68,8 +72,9 @@ public final class LocationTimeZoneEvent implements Parcelable {
private final long mElapsedRealtimeNanos;
- private LocationTimeZoneEvent(@EventType int eventType, @NonNull List<String> timeZoneIds,
- long elapsedRealtimeNanos) {
+ private LocationTimeZoneEvent(@NonNull UserHandle userHandle, @EventType int eventType,
+ @NonNull List<String> timeZoneIds, long elapsedRealtimeNanos) {
+ mUserHandle = Objects.requireNonNull(userHandle);
mEventType = checkValidEventType(eventType);
mTimeZoneIds = immutableList(timeZoneIds);
@@ -83,6 +88,14 @@ public final class LocationTimeZoneEvent implements Parcelable {
}
/**
+ * Returns the current user when the event was generated.
+ */
+ @NonNull
+ public UserHandle getUserHandle() {
+ return mUserHandle;
+ }
+
+ /**
* Returns the time of this fix, in elapsed real-time since system boot.
*
* <p>This value can be reliably compared to {@link
@@ -117,7 +130,8 @@ public final class LocationTimeZoneEvent implements Parcelable {
@Override
public String toString() {
return "LocationTimeZoneEvent{"
- + "mEventType=" + mEventType
+ + "mUserHandle=" + mUserHandle
+ + ", mEventType=" + mEventType
+ ", mTimeZoneIds=" + mTimeZoneIds
+ ", mElapsedRealtimeNanos=" + mElapsedRealtimeNanos
+ '}';
@@ -127,12 +141,14 @@ public final class LocationTimeZoneEvent implements Parcelable {
new Parcelable.Creator<LocationTimeZoneEvent>() {
@Override
public LocationTimeZoneEvent createFromParcel(Parcel in) {
+ UserHandle userHandle = UserHandle.readFromParcel(in);
int eventType = in.readInt();
@SuppressWarnings("unchecked")
ArrayList<String> timeZoneIds =
(ArrayList<String>) in.readArrayList(null /* classLoader */);
long elapsedRealtimeNanos = in.readLong();
- return new LocationTimeZoneEvent(eventType, timeZoneIds, elapsedRealtimeNanos);
+ return new LocationTimeZoneEvent(
+ userHandle, eventType, timeZoneIds, elapsedRealtimeNanos);
}
@Override
@@ -148,6 +164,7 @@ public final class LocationTimeZoneEvent implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int flags) {
+ mUserHandle.writeToParcel(parcel, flags);
parcel.writeInt(mEventType);
parcel.writeList(mTimeZoneIds);
parcel.writeLong(mElapsedRealtimeNanos);
@@ -162,19 +179,21 @@ public final class LocationTimeZoneEvent implements Parcelable {
return false;
}
LocationTimeZoneEvent that = (LocationTimeZoneEvent) o;
- return mEventType == that.mEventType
+ return mUserHandle.equals(that.mUserHandle)
+ && mEventType == that.mEventType
&& mElapsedRealtimeNanos == that.mElapsedRealtimeNanos
&& mTimeZoneIds.equals(that.mTimeZoneIds);
}
@Override
public int hashCode() {
- return Objects.hash(mEventType, mTimeZoneIds, mElapsedRealtimeNanos);
+ return Objects.hash(mUserHandle, mEventType, mTimeZoneIds, mElapsedRealtimeNanos);
}
/** @hide */
public static final class Builder {
+ private UserHandle mUserHandle;
private @EventType int mEventType = EVENT_TYPE_UNKNOWN;
private @NonNull List<String> mTimeZoneIds = Collections.emptyList();
private long mElapsedRealtimeNanos;
@@ -186,13 +205,22 @@ public final class LocationTimeZoneEvent implements Parcelable {
* Sets the contents of this from the supplied instance.
*/
public Builder(@NonNull LocationTimeZoneEvent ltz) {
+ mUserHandle = ltz.mUserHandle;
mEventType = ltz.mEventType;
mTimeZoneIds = ltz.mTimeZoneIds;
mElapsedRealtimeNanos = ltz.mElapsedRealtimeNanos;
}
/**
- * Set the time zone ID of this fix.
+ * Set the current user when this event was generated.
+ */
+ public Builder setUserHandle(@NonNull UserHandle userHandle) {
+ mUserHandle = Objects.requireNonNull(userHandle);
+ return this;
+ }
+
+ /**
+ * Set the time zone ID of this event.
*/
public Builder setEventType(@EventType int eventType) {
checkValidEventType(eventType);
@@ -201,7 +229,7 @@ public final class LocationTimeZoneEvent implements Parcelable {
}
/**
- * Sets the time zone IDs of this fix.
+ * Sets the time zone IDs of this event.
*/
public Builder setTimeZoneIds(@NonNull List<String> timeZoneIds) {
mTimeZoneIds = Objects.requireNonNull(timeZoneIds);
@@ -209,9 +237,7 @@ public final class LocationTimeZoneEvent implements Parcelable {
}
/**
- * Sets the time of this fix, in elapsed real-time since system boot.
- *
- * @param time elapsed real-time of fix, in nanoseconds since system boot.
+ * Sets the time of this event, in elapsed real-time since system boot.
*/
public Builder setElapsedRealtimeNanos(long time) {
mElapsedRealtimeNanos = time;
@@ -222,8 +248,8 @@ public final class LocationTimeZoneEvent implements Parcelable {
* Builds a {@link LocationTimeZoneEvent} instance.
*/
public LocationTimeZoneEvent build() {
- return new LocationTimeZoneEvent(this.mEventType, this.mTimeZoneIds,
- this.mElapsedRealtimeNanos);
+ return new LocationTimeZoneEvent(
+ mUserHandle, mEventType, mTimeZoneIds, mElapsedRealtimeNanos);
}
}
diff --git a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java
index 0143c88e0898..c533c20d07e3 100644
--- a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java
+++ b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java
@@ -32,7 +32,7 @@ import java.util.Objects;
/**
* Base class for location time zone providers implemented as unbundled services.
*
- * TODO Provide details of the expected service actions.
+ * TODO(b/152744911): Provide details of the expected service actions and threading.
*
* <p>IMPORTANT: This class is effectively a public API for unbundled applications, and must remain
* API stable.
diff --git a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java
index dd80466637e6..e898bbf3ecc0 100644
--- a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java
+++ b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java
@@ -44,6 +44,24 @@ public final class LocationTimeZoneProviderRequestUnbundled {
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ LocationTimeZoneProviderRequestUnbundled that =
+ (LocationTimeZoneProviderRequestUnbundled) o;
+ return mRequest.equals(that.mRequest);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRequest);
+ }
+
+ @Override
public String toString() {
return mRequest.toString();
}
diff --git a/media/java/android/media/MediaTranscodeManager.java b/media/java/android/media/MediaTranscodeManager.java
index e1bff03f6833..4e2ae5c471f4 100644
--- a/media/java/android/media/MediaTranscodeManager.java
+++ b/media/java/android/media/MediaTranscodeManager.java
@@ -36,7 +36,10 @@ import com.android.internal.annotations.VisibleForTesting;
import java.io.FileNotFoundException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
@@ -94,11 +97,17 @@ import java.util.concurrent.Executors;
TODO(hkuang): Clarify whether supports framerate conversion.
@hide
*/
-public final class MediaTranscodeManager {
+public final class MediaTranscodeManager implements AutoCloseable {
private static final String TAG = "MediaTranscodeManager";
private static final String MEDIA_TRANSCODING_SERVICE = "media.transcoding";
+ /** Maximum number of retry to connect to the service. */
+ private static final int CONNECT_SERVICE_RETRY_COUNT = 100;
+
+ /** Interval between trying to reconnect to the service. */
+ private static final int INTERVAL_CONNECT_SERVICE_RETRY_MS = 40;
+
/**
* Default transcoding type.
* @hide
@@ -117,6 +126,25 @@ public final class MediaTranscodeManager {
*/
public static final int TRANSCODING_TYPE_IMAGE = 2;
+ @Override
+ public void close() throws Exception {
+ release();
+ }
+
+ /**
+ * Releases the MediaTranscodeManager.
+ */
+ //TODO(hkuang): add test for it.
+ private void release() throws Exception {
+ synchronized (mLock) {
+ if (mTranscodingClient != null) {
+ mTranscodingClient.unregister();
+ } else {
+ throw new UnsupportedOperationException("Failed to release");
+ }
+ }
+ }
+
/** @hide */
@IntDef(prefix = {"TRANSCODING_TYPE_"}, value = {
TRANSCODING_TYPE_UNKNOWN,
@@ -181,10 +209,12 @@ public final class MediaTranscodeManager {
private final String mPackageName;
private final int mPid;
private final int mUid;
- private final ExecutorService mCallbackExecutor = Executors.newSingleThreadExecutor();
- private static MediaTranscodeManager sMediaTranscodeManager;
+ private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
private final HashMap<Integer, TranscodingJob> mPendingTranscodingJobs = new HashMap();
- @NonNull private ITranscodingClient mTranscodingClient;
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ @NonNull private ITranscodingClient mTranscodingClient = null;
+ private static MediaTranscodeManager sMediaTranscodeManager;
private void handleTranscodingFinished(int jobId, TranscodingResultParcel result) {
synchronized (mPendingTranscodingJobs) {
@@ -209,7 +239,7 @@ public final class MediaTranscodeManager {
}
}
- private void handleTranscodingFailed(int jobId, int errorCodec) {
+ private void handleTranscodingFailed(int jobId, int errorCode) {
synchronized (mPendingTranscodingJobs) {
// Gets the job associated with the jobId and removes it from
// mPendingTranscodingJobs.
@@ -254,6 +284,98 @@ public final class MediaTranscodeManager {
}
}
+ private static IMediaTranscodingService getService(boolean retry) {
+ int retryCount = !retry ? 1 : CONNECT_SERVICE_RETRY_COUNT;
+ Log.i(TAG, "get service with rety " + retryCount);
+ for (int count = 1; count <= retryCount; count++) {
+ Log.d(TAG, "Trying to connect to service. Try count: " + count);
+ IMediaTranscodingService service = IMediaTranscodingService.Stub.asInterface(
+ ServiceManager.getService(MEDIA_TRANSCODING_SERVICE));
+ if (service != null) {
+ return service;
+ }
+ try {
+ // Sleep a bit before retry.
+ Thread.sleep(INTERVAL_CONNECT_SERVICE_RETRY_MS);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+
+ throw new UnsupportedOperationException("Failed to connect to MediaTranscoding service");
+ }
+
+ /*
+ * Handle client binder died event.
+ * Upon receiving a binder died event of the client, we will do the following:
+ * 1) For the job that is running, notify the client that the job is failed with error code,
+ * so client could choose to retry the job or not.
+ * TODO(hkuang): Add a new error code to signal service died error.
+ * 2) For the jobs that is still pending or paused, we will resubmit the job internally once
+ * we successfully reconnect to the service and register a new client.
+ * 3) When trying to connect to the service and register a new client. The service may need time
+ * to reboot or never boot up again. So we will retry for a number of times. If we still
+ * could not connect, we will notify client job failure for the pending and paused jobs.
+ */
+ private void onClientDied() {
+ synchronized (mLock) {
+ mTranscodingClient = null;
+ }
+
+ // Delegates the job notification and retry to the executor as it may take some time.
+ mExecutor.execute(() -> {
+ // List to track the jobs that we want to retry.
+ List<TranscodingJob> retryJobs = new ArrayList<TranscodingJob>();
+
+ // First notify the client of job failure for all the running jobs.
+ synchronized (mPendingTranscodingJobs) {
+ for (Map.Entry<Integer, TranscodingJob> entry :
+ mPendingTranscodingJobs.entrySet()) {
+ TranscodingJob job = entry.getValue();
+
+ if (job.getStatus() == TranscodingJob.STATUS_RUNNING) {
+ job.updateStatusAndResult(TranscodingJob.STATUS_FINISHED,
+ TranscodingJob.RESULT_ERROR);
+
+ // Remove the job from pending jobs.
+ mPendingTranscodingJobs.remove(entry.getKey());
+
+ if (job.mListener != null && job.mListenerExecutor != null) {
+ Log.i(TAG, "Notify client job failed");
+ job.mListenerExecutor.execute(
+ () -> job.mListener.onTranscodingFinished(job));
+ }
+ } else if (job.getStatus() == TranscodingJob.STATUS_PENDING
+ || job.getStatus() == TranscodingJob.STATUS_PAUSED) {
+ // Add the job to retryJobs to handle them later.
+ retryJobs.add(job);
+ }
+ }
+ }
+
+ // Try to register with the service once it boots up.
+ IMediaTranscodingService service = getService(true /*retry*/);
+ boolean haveTranscodingClient = false;
+ if (service != null) {
+ synchronized (mLock) {
+ mTranscodingClient = registerClient(service);
+ if (mTranscodingClient != null) {
+ haveTranscodingClient = true;
+ }
+ }
+ }
+
+ for (TranscodingJob job : retryJobs) {
+ // Notify the job failure if we fails to connect to the service or fail
+ // to retry the job.
+ if (!haveTranscodingClient || !job.retry()) {
+ // TODO(hkuang): Return correct error code to the client.
+ handleTranscodingFailed(job.getJobId(), 0 /*unused */);
+ }
+ }
+ });
+ }
+
private void updateStatus(int jobId, int status) {
synchronized (mPendingTranscodingJobs) {
final TranscodingJob job = mPendingTranscodingJobs.get(jobId);
@@ -336,6 +458,30 @@ public final class MediaTranscodeManager {
}
};
+ private ITranscodingClient registerClient(IMediaTranscodingService service)
+ throws UnsupportedOperationException {
+ synchronized (mLock) {
+ try {
+ // Registers the client with MediaTranscoding service.
+ mTranscodingClient = service.registerClient(
+ mTranscodingClientCallback,
+ mPackageName,
+ mPackageName,
+ IMediaTranscodingService.USE_CALLING_UID,
+ IMediaTranscodingService.USE_CALLING_PID);
+
+ if (mTranscodingClient != null) {
+ mTranscodingClient.asBinder().linkToDeath(() -> onClientDied(), /* flags */ 0);
+ }
+ return mTranscodingClient;
+ } catch (RemoteException re) {
+ Log.e(TAG, "Failed to register new client due to exception " + re);
+ mTranscodingClient = null;
+ }
+ }
+ throw new UnsupportedOperationException("Failed to register new client");
+ }
+
/* Private constructor. */
private MediaTranscodeManager(@NonNull Context context,
IMediaTranscodingService transcodingService) {
@@ -344,22 +490,18 @@ public final class MediaTranscodeManager {
mPackageName = mContext.getPackageName();
mPid = Os.getuid();
mUid = Os.getpid();
+ mTranscodingClient = registerClient(transcodingService);
+ }
+ @Override
+ protected void finalize() {
try {
- // Registers the client with MediaTranscoding service.
- mTranscodingClient = transcodingService.registerClient(
- mTranscodingClientCallback,
- mPackageName,
- mPackageName,
- IMediaTranscodingService.USE_CALLING_UID,
- IMediaTranscodingService.USE_CALLING_PID);
- } catch (RemoteException re) {
- Log.e(TAG, "Failed to register new client due to exception " + re);
- throw new UnsupportedOperationException("Failed to register new client");
+ release();
+ } catch (Exception ex) {
+ Log.e(TAG, "Failed to release");
}
}
-
public static final class TranscodingRequest {
/** Uri of the source media file. */
private @NonNull Uri mSourceUri;
@@ -807,6 +949,16 @@ public final class MediaTranscodeManager {
}
/**
+ * Resubmit the transcoding job to the service.
+ *
+ * @return true if successfully resubmit the job to the service. False otherwise.
+ */
+ public synchronized boolean retry() {
+ // TODO(hkuang): Implement this.
+ return true;
+ }
+
+ /**
* Cancels the transcoding job and notify the listener.
* If the job happened to finish before being canceled this call is effectively a no-op and
* will not update the result in that case.
@@ -879,9 +1031,15 @@ public final class MediaTranscodeManager {
*/
public static MediaTranscodeManager getInstance(@NonNull Context context) {
// Acquires the MediaTranscoding service.
- IMediaTranscodingService service = IMediaTranscodingService.Stub.asInterface(
- ServiceManager.getService(MEDIA_TRANSCODING_SERVICE));
+ IMediaTranscodingService service = getService(false /*retry*/);
+ return getInstance(context, service);
+ }
+ /** Similar as above, but wait till the service is ready. */
+ @VisibleForTesting
+ public static MediaTranscodeManager getInstance(@NonNull Context context, boolean retry) {
+ // Acquires the MediaTranscoding service.
+ IMediaTranscodingService service = getService(retry);
return getInstance(context, service);
}
@@ -896,6 +1054,7 @@ public final class MediaTranscodeManager {
sMediaTranscodeManager = new MediaTranscodeManager(context.getApplicationContext(),
transcodingService);
}
+
return sMediaTranscodeManager;
}
}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 6c41f7bcd0bc..549e79353133 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -103,6 +103,8 @@ public final class MediaSession {
* System only flag for a session that needs to have priority over all other
* sessions. This flag ensures this session will receive media button events
* regardless of the current ordering in the system.
+ * If there are two or more sessions with this flag, the last session that sets this flag
+ * will be the global priority session.
*
* @hide
*/
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 5770c6797404..5db672993df1 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -2060,7 +2060,7 @@ static FrontendSettings getDvbcFrontendSettings(JNIEnv *env, const jobject& sett
env->GetIntField(settings, env->GetFieldID(clazz, "mModulation", "I")));
FrontendInnerFec innerFec =
static_cast<FrontendInnerFec>(
- env->GetLongField(settings, env->GetFieldID(clazz, "mFec", "J")));
+ env->GetLongField(settings, env->GetFieldID(clazz, "mInnerFec", "J")));
uint32_t symbolRate =
static_cast<uint32_t>(
env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I")));
@@ -2069,7 +2069,7 @@ static FrontendSettings getDvbcFrontendSettings(JNIEnv *env, const jobject& sett
env->GetIntField(settings, env->GetFieldID(clazz, "mOuterFec", "I")));
FrontendDvbcAnnex annex =
static_cast<FrontendDvbcAnnex>(
- env->GetByteField(settings, env->GetFieldID(clazz, "mAnnex", "B")));
+ env->GetIntField(settings, env->GetFieldID(clazz, "mAnnex", "I")));
FrontendDvbcSpectralInversion spectralInversion =
static_cast<FrontendDvbcSpectralInversion>(
env->GetIntField(
diff --git a/media/tests/MediaTranscodingTest/Android.bp b/media/tests/MediaTranscodingTest/Android.bp
index fcf8f11f6625..907c3c8b4933 100644
--- a/media/tests/MediaTranscodingTest/Android.bp
+++ b/media/tests/MediaTranscodingTest/Android.bp
@@ -8,6 +8,7 @@ android_test {
static_libs: [
"androidx.test.ext.junit",
"androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
"android-support-test",
"testng"
],
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
index 8fe10888cab6..009a41ee004a 100644
--- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
@@ -23,15 +23,23 @@ import android.media.MediaTranscodeManager;
import android.media.MediaTranscodeManager.TranscodingJob;
import android.media.MediaTranscodeManager.TranscodingRequest;
import android.net.Uri;
+import android.os.Bundle;
import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.uiautomator.UiDevice;
+
import org.junit.Test;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
@@ -127,8 +135,9 @@ public class MediaTranscodeManagerTest
super.setUp();
mContext = getInstrumentation().getContext();
- mMediaTranscodeManager = MediaTranscodeManager.getInstance(mContext);
+ mMediaTranscodeManager = MediaTranscodeManager.getInstance(mContext, true /*retry*/);
assertNotNull(mMediaTranscodeManager);
+ androidx.test.InstrumentationRegistry.registerInstance(getInstrumentation(), new Bundle());
// Setup source HEVC file uri.
mSourceHEVCVideoUri = resourceToUri(mContext, R.raw.VideoOnlyHEVC, "VideoOnlyHEVC.mp4");
@@ -148,8 +157,6 @@ public class MediaTranscodeManagerTest
@Test
public void testTranscodingFromHevcToAvc() throws Exception {
- Log.d(TAG, "Starting: testMediaTranscodeManager");
-
Semaphore transcodeCompleteSemaphore = new Semaphore(0);
// Create a file Uri: file:///data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
@@ -194,6 +201,7 @@ public class MediaTranscodeManagerTest
stats.mAveragePSNR >= PSNR_THRESHOLD);
}
+
@Test
public void testCancelTranscoding() throws Exception {
Log.d(TAG, "Starting: testMediaTranscodeManager");
@@ -300,5 +308,94 @@ public class MediaTranscodeManagerTest
assertTrue("Failed to receive at least 10 progress updates",
progressUpdateCount.get() > 10);
}
+
+ // [[ $(adb shell whoami) == "root" ]]
+ private boolean checkIfRoot() throws IOException {
+ try (ParcelFileDescriptor result = getInstrumentation().getUiAutomation()
+ .executeShellCommand("whoami");
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
+ new FileInputStream(result.getFileDescriptor())))) {
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ if (line.contains("root")) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private String executeShellCommand(String cmd) throws Exception {
+ return UiDevice.getInstance(
+ InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
+ }
+
+ @Test
+ public void testHandleTranscoderServiceDied() throws Exception {
+ try {
+ if (!checkIfRoot()) {
+ throw new AssertionError("must be root to run this test; try adb root?");
+ } else {
+ Log.i(TAG, "Device is root");
+ }
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+
+ Semaphore transcodeCompleteSemaphore = new Semaphore(0);
+ Semaphore jobStartedSemaphore = new Semaphore(0);
+
+ // Transcode a 15 seconds video, so that the transcoding is not finished when we kill the
+ // service.
+ Uri srcUri = Uri.parse(ContentResolver.SCHEME_FILE + "://"
+ + mContext.getCacheDir().getAbsolutePath() + "/longtest_15s.mp4");
+ Uri destinationUri = Uri.parse(ContentResolver.SCHEME_FILE + "://"
+ + mContext.getCacheDir().getAbsolutePath() + "/HevcTranscode.mp4");
+
+ TranscodingRequest request =
+ new TranscodingRequest.Builder()
+ .setSourceUri(mSourceHEVCVideoUri)
+ .setDestinationUri(destinationUri)
+ .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+ .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+ .setVideoTrackFormat(createMediaFormat())
+ .build();
+ Executor listenerExecutor = Executors.newSingleThreadExecutor();
+
+ Log.i(TAG, "transcoding to " + createMediaFormat());
+
+ TranscodingJob job = mMediaTranscodeManager.enqueueRequest(request, listenerExecutor,
+ transcodingJob -> {
+ Log.d(TAG, "Transcoding completed with result: " + transcodingJob.getResult());
+ assertEquals(transcodingJob.getResult(), TranscodingJob.RESULT_ERROR);
+ transcodeCompleteSemaphore.release();
+ });
+ assertNotNull(job);
+
+ AtomicInteger progressUpdateCount = new AtomicInteger(0);
+
+ // Set progress update executor and use the same executor as result listener.
+ job.setOnProgressUpdateListener(listenerExecutor,
+ new TranscodingJob.OnProgressUpdateListener() {
+ @Override
+ public void onProgressUpdate(int newProgress) {
+ if (newProgress > 0) {
+ jobStartedSemaphore.release();
+ }
+ }
+ });
+
+ // Wait for progress update so the job is in running state.
+ jobStartedSemaphore.tryAcquire(TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue("Job is not running", job.getStatus() == TranscodingJob.STATUS_RUNNING);
+
+ // Kills the service and expects receiving failure of the job.
+ executeShellCommand("pkill -f media.transcoding");
+
+ Log.d(TAG, "testMediaTranscodeManager - Waiting for transcode result.");
+ boolean finishedOnTime = transcodeCompleteSemaphore.tryAcquire(
+ TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue("Invalid job status", job.getStatus() == TranscodingJob.STATUS_FINISHED);
+ }
}
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index e90fbd4dead8..e0ebec6cbd01 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -11901,8 +11901,8 @@ package android.content.pm {
field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR;
field public static final int INVALID_ID = -1; // 0xffffffff
field public static final int STAGED_SESSION_ACTIVATION_FAILED = 2; // 0x2
+ field public static final int STAGED_SESSION_CONFLICT = 4; // 0x4
field public static final int STAGED_SESSION_NO_ERROR = 0; // 0x0
- field public static final int STAGED_SESSION_OTHER_ERROR = 4; // 0x4
field public static final int STAGED_SESSION_UNKNOWN = 3; // 0x3
field public static final int STAGED_SESSION_VERIFICATION_FAILED = 1; // 0x1
}
@@ -14250,6 +14250,10 @@ package android.graphics {
enum_constant public static final android.graphics.BlurMaskFilter.Blur SOLID;
}
+ public final class BlurShader extends android.graphics.Shader {
+ ctor public BlurShader(float, float, @Nullable android.graphics.Shader);
+ }
+
public class Camera {
ctor public Camera();
method public void applyToCanvas(android.graphics.Canvas);
@@ -35282,9 +35286,11 @@ package android.os {
public final class PowerManager {
method public void addThermalStatusListener(@NonNull android.os.PowerManager.OnThermalStatusChangedListener);
method public void addThermalStatusListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.PowerManager.OnThermalStatusChangedListener);
+ method @Nullable public java.time.Duration getBatteryDischargePrediction();
method public int getCurrentThermalStatus();
method public int getLocationPowerSaveMode();
method public float getThermalHeadroom(@IntRange(from=0, to=60) int);
+ method public boolean isBatteryDischargePredictionPersonalized();
method public boolean isDeviceIdleMode();
method public boolean isIgnoringBatteryOptimizations(String);
method public boolean isInteractive();
@@ -45986,6 +45992,7 @@ package android.telephony {
method public void onDataConnectionStateChanged(int);
method public void onDataConnectionStateChanged(int, int);
method @RequiresPermission("android.permission.READ_PHONE_STATE") public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
+ method public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
method public void onMessageWaitingIndicatorChanged(boolean);
method @RequiresPermission("android.permission.MODIFY_PHONE_STATE") public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
@@ -46502,7 +46509,9 @@ package android.telephony {
method @Deprecated public String iccTransmitApduBasicChannel(int, int, int, int, int, String);
method @Deprecated public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
method public boolean isConcurrentVoiceAndDataSupported();
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isDataConnectionAllowed();
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean isDataEnabled();
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledForReason(int);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
method public boolean isEmergencyNumber(@NonNull String);
method public boolean isHearingAidCompatibilitySupported();
@@ -46524,6 +46533,7 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledForReason(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setForbiddenPlmns(@NonNull java.util.List<java.lang.String>);
method public boolean setLine1NumberForDisplay(String, String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setNetworkSelectionModeAutomatic();
@@ -46571,6 +46581,10 @@ package android.telephony {
field public static final int DATA_CONNECTING = 1; // 0x1
field public static final int DATA_DISCONNECTED = 0; // 0x0
field public static final int DATA_DISCONNECTING = 4; // 0x4
+ field public static final int DATA_ENABLED_REASON_CARRIER = 2; // 0x2
+ field public static final int DATA_ENABLED_REASON_POLICY = 1; // 0x1
+ field public static final int DATA_ENABLED_REASON_THERMAL = 3; // 0x3
+ field public static final int DATA_ENABLED_REASON_USER = 0; // 0x0
field public static final int DATA_SUSPENDED = 3; // 0x3
field public static final int DATA_UNKNOWN = -1; // 0xffffffff
field public static final String EXTRA_ACTIVE_SIM_SUPPORTED_COUNT = "android.telephony.extra.ACTIVE_SIM_SUPPORTED_COUNT";
@@ -53328,7 +53342,7 @@ package android.view {
}
public class ViewPropertyAnimator {
- method public android.view.ViewPropertyAnimator alpha(float);
+ method public android.view.ViewPropertyAnimator alpha(@FloatRange(from=0.0f, to=1.0f) float);
method public android.view.ViewPropertyAnimator alphaBy(float);
method public void cancel();
method public long getDuration();
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 3fd0ee1c8011..d1264dfdd36d 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -7298,6 +7298,7 @@ package android.os {
method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplaySuppressedForToken(@NonNull String);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSaveEnabled(boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSavePolicy(@NonNull android.os.BatterySaverPolicyConfig);
+ method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void setBatteryDischargePrediction(@NonNull java.time.Duration, boolean);
method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setDynamicPowerSaveHint(boolean, int);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveModeEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void suppressAmbientDisplay(@NonNull String, boolean);
@@ -9682,7 +9683,8 @@ package android.telephony {
public class PhoneStateListener {
method public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
- method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
+ method @Deprecated public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
+ method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber);
method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
method public void onRadioPowerStateChanged(int);
@@ -10099,10 +10101,8 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataConnectionAllowed();
method public boolean isDataConnectivityPossible();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledWithReason(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean isIccLockEnabled();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
@@ -10134,7 +10134,6 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledWithReason(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean);
@@ -10172,10 +10171,6 @@ package android.telephony {
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
- field public static final int DATA_ENABLED_REASON_CARRIER = 2; // 0x2
- field public static final int DATA_ENABLED_REASON_POLICY = 1; // 0x1
- field public static final int DATA_ENABLED_REASON_THERMAL = 3; // 0x3
- field public static final int DATA_ENABLED_REASON_USER = 0; // 0x0
field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION";
field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID";
field public static final String EXTRA_PHONE_IN_ECM_STATE = "android.telephony.extra.PHONE_IN_ECM_STATE";
@@ -11585,8 +11580,8 @@ package android.webkit {
public interface PacProcessor {
method @Nullable public String findProxyForUrl(@NonNull String);
method @NonNull public static android.webkit.PacProcessor getInstance();
- method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(long);
- method public default long getNetworkHandle();
+ method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(@Nullable android.net.Network);
+ method @Nullable public default android.net.Network getNetwork();
method public default void releasePacProcessor();
method public boolean setProxyScript(@NonNull String);
}
@@ -11727,7 +11722,7 @@ package android.webkit {
method public android.webkit.CookieManager getCookieManager();
method public android.webkit.GeolocationPermissions getGeolocationPermissions();
method @NonNull public default android.webkit.PacProcessor getPacProcessor();
- method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(long);
+ method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(@Nullable android.net.Network);
method public android.webkit.ServiceWorkerController getServiceWorkerController();
method public android.webkit.WebViewFactoryProvider.Statics getStatics();
method @Deprecated public android.webkit.TokenBindingService getTokenBindingService();
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index 039f2c039ded..d3277ded6c5b 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -121,7 +121,6 @@
<string-array name="config_systemUIServiceComponentsExclude" translatable="false">
<item>com.android.systemui.recents.Recents</item>
<item>com.android.systemui.volume.VolumeUI</item>
- <item>com.android.systemui.stackdivider.Divider</item>
<item>com.android.systemui.statusbar.phone.StatusBar</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
<item>com.android.systemui.pip.PipUI</item>
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml b/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml
index b8e1edc46da7..20aa5f79c5cc 100644
--- a/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml
+++ b/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml
@@ -22,7 +22,8 @@
<item target="attr/icon" value="@attr/icon"/>
<item target="attr/selectedIcon" value="@attr/selectedIcon"/>
- <item target="attr/intent" value="@attr/longIntent"/>
+ <item target="attr/intent" value="@attr/intent"/>
+ <item target="attr/longIntent" value="@attr/longIntent"/>
<item target="attr/componentNames" value="@attr/componentNames"/>
<item target="attr/highlightWhenSelected" value="@attr/highlightWhenSelected"/>
<item target="attr/categories" value="@attr/categories"/>
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
index b2f98ecde513..24d9d09d2ca9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
@@ -22,7 +22,6 @@ import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.SystemServicesModule;
import com.android.systemui.dagger.SystemUIModule;
-import com.android.systemui.onehanded.dagger.OneHandedModule;
import com.android.systemui.pip.phone.dagger.PipModule;
import dagger.Subcomponent;
@@ -36,7 +35,6 @@ import dagger.Subcomponent;
DependencyProvider.class,
DependencyBinder.class,
PipModule.class,
- OneHandedModule.class,
SystemServicesModule.class,
SystemUIModule.class,
CarSystemUIModule.class,
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
index 797a178c9a4b..3971e18bb968 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
@@ -34,7 +34,6 @@ import com.android.systemui.power.PowerUI;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsModule;
import com.android.systemui.shortcut.ShortcutKeyDispatcher;
-import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.InstantAppNotifier;
import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
@@ -42,6 +41,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.theme.ThemeOverlayController;
import com.android.systemui.toast.ToastUI;
import com.android.systemui.util.leak.GarbageMonitor;
+import com.android.systemui.wmshell.WMShell;
import dagger.Binds;
import dagger.Module;
@@ -59,12 +59,6 @@ public abstract class CarSystemUIBinder {
@ClassKey(AuthController.class)
public abstract SystemUI bindAuthController(AuthController sysui);
- /** Inject into Divider. */
- @Binds
- @IntoMap
- @ClassKey(Divider.class)
- public abstract SystemUI bindDivider(Divider sysui);
-
/** Inject Car Navigation Bar. */
@Binds
@IntoMap
@@ -192,4 +186,10 @@ public abstract class CarSystemUIBinder {
@IntoMap
@ClassKey(SideLoadedAppController.class)
public abstract SystemUI bindSideLoadedAppController(SideLoadedAppController sysui);
+
+ /** Inject into WMShell. */
+ @Binds
+ @IntoMap
+ @ClassKey(WMShell.class)
+ public abstract SystemUI bindWMShell(WMShell sysui);
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 290700fad147..3eea5132da1d 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -47,7 +47,6 @@ import com.android.systemui.qs.dagger.QSModule;
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImplementation;
-import com.android.systemui.stackdivider.DividerModule;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
@@ -75,7 +74,6 @@ import dagger.Provides;
@Module(
includes = {
- DividerModule.class,
QSModule.class,
CarWMShellModule.class
})
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
index 143c444fc4be..b8bf825bdcc1 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
@@ -29,6 +29,8 @@ import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
+import com.android.systemui.car.notification.BottomNotificationPanelViewMediator;
+import com.android.systemui.car.notification.TopNotificationPanelViewMediator;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -95,6 +97,7 @@ public class SystemBarConfigs {
populateMaps();
readConfigs();
checkEnabledBarsHaveUniqueBarTypes();
+ checkSystemBarEnabledForNotificationPanel();
setInsetPaddingsForOverlappingCorners();
sortSystemBarSidesByZOrder();
}
@@ -221,6 +224,34 @@ public class SystemBarConfigs {
}
}
+ private void checkSystemBarEnabledForNotificationPanel() throws RuntimeException {
+
+ String notificationPanelMediatorName =
+ mResources.getString(R.string.config_notificationPanelViewMediator);
+ if (notificationPanelMediatorName == null) {
+ return;
+ }
+
+ Class<?> notificationPanelMediatorUsed = null;
+ try {
+ notificationPanelMediatorUsed = Class.forName(notificationPanelMediatorName);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ if (!mTopNavBarEnabled && notificationPanelMediatorUsed.isAssignableFrom(
+ TopNotificationPanelViewMediator.class)) {
+ throw new RuntimeException(
+ "Top System Bar must be enabled to use " + notificationPanelMediatorName);
+ }
+
+ if (!mBottomNavBarEnabled && notificationPanelMediatorUsed.isAssignableFrom(
+ BottomNotificationPanelViewMediator.class)) {
+ throw new RuntimeException("Bottom System Bar must be enabled to use "
+ + notificationPanelMediatorName);
+ }
+ }
+
private void setInsetPaddingsForOverlappingCorners() {
setInsetPaddingForOverlappingCorner(TOP, LEFT);
setInsetPaddingForOverlappingCorner(TOP, RIGHT);
@@ -277,7 +308,7 @@ public class SystemBarConfigs {
}
private static boolean isHorizontalBar(@SystemBarSide int side) {
- return side == TOP || side == BOTTOM;
+ return side == TOP || side == BOTTOM;
}
private static boolean isVerticalBar(@SystemBarSide int side) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
index e493c97a9b46..c7354ed5b459 100644
--- a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
@@ -49,7 +49,7 @@ public class DisplaySystemBarsController extends DisplayImeController {
private final Context mContext;
private SparseArray<PerDisplay> mPerDisplaySparseArray;
- private DisplaySystemBarsController(
+ public DisplaySystemBarsController(
Context context,
IWindowManager wmService,
DisplayController displayController,
@@ -167,33 +167,4 @@ public class DisplaySystemBarsController extends DisplayImeController {
}
}
}
-
- /** Builds {@link DisplaySystemBarsController} instance. */
- public static class Builder {
- private Context mContext;
- private IWindowManager mWmService;
- private DisplayController mDisplayController;
- private Handler mHandler;
- private TransactionPool mTransactionPool;
-
- public Builder(Context context, IWindowManager wmService,
- DisplayController displayController, Handler handler,
- TransactionPool transactionPool) {
- mContext = context;
- mWmService = wmService;
- mDisplayController = displayController;
- mHandler = handler;
- mTransactionPool = transactionPool;
- }
-
- /** Builds and initializes {@link DisplaySystemBarsController} instance. */
- public DisplaySystemBarsController build() {
- DisplaySystemBarsController displaySystemBarsController =
- new DisplaySystemBarsController(
- mContext, mWmService, mDisplayController, mHandler, mTransactionPool);
- // Separates startMonitorDisplays from constructor to prevent circular init issue.
- displaySystemBarsController.startMonitorDisplays();
- return displaySystemBarsController;
- }
- }
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java b/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
index 2324c3d59155..fd6685ffdb8f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
@@ -40,8 +40,8 @@ public class CarWMShellModule {
DisplayImeController provideDisplayImeController(Context context,
IWindowManager wmService, DisplayController displayController,
@Main Handler mainHandler, TransactionPool transactionPool) {
- return new DisplaySystemBarsController.Builder(context, wmService, displayController,
- mainHandler, transactionPool).build();
+ return new DisplaySystemBarsController(context, wmService, displayController,
+ mainHandler, transactionPool);
}
/** TODO(b/150319024): PipMenuActivity will move to a Window */
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
index b65578dbe02c..391f75e35382 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
@@ -64,13 +64,13 @@ public class DisplaySystemBarsControllerTest extends SysuiTestCase {
public void setUp() {
MockitoAnnotations.initMocks(this);
- mController = new DisplaySystemBarsController.Builder(
+ mController = new DisplaySystemBarsController(
mContext,
mIWindowManager,
mDisplayController,
mHandler,
mTransactionPool
- ).build();
+ );
}
@Test
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index f80e934cf37c..9ff868467531 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -352,16 +352,18 @@ public class DynamicSystemInstallationService extends Service
if (powerManager != null) {
powerManager.reboot("dynsystem");
}
- } else {
- Log.e(TAG, "Failed to enable DynamicSystem because of native runtime error.");
- mNM.cancel(NOTIFICATION_ID);
+ return;
+ }
- Toast.makeText(this,
- getString(R.string.toast_failed_to_reboot_to_dynsystem),
- Toast.LENGTH_LONG).show();
+ Log.e(TAG, "Failed to enable DynamicSystem because of native runtime error.");
- mDynSystem.remove();
- }
+ Toast.makeText(this,
+ getString(R.string.toast_failed_to_reboot_to_dynsystem),
+ Toast.LENGTH_LONG).show();
+
+ postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_EXCEPTION, null);
+ resetTaskAndStop();
+ mDynSystem.remove();
}
private void executeRebootToNormalCommand() {
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index 596947dfb6dc..719fc9219450 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -31,7 +31,7 @@
<string name="template_all_pages" msgid="3322235982020148762">"همه <xliff:g id="PAGE_COUNT">%1$s</xliff:g> صفحه"</string>
<string name="template_page_range" msgid="428638530038286328">"محدوده <xliff:g id="PAGE_COUNT">%1$s</xliff:g> صفحه"</string>
<string name="pages_range_example" msgid="8558694453556945172">"‏‏‎مثلاً ۱—۵،‏۹،۷—۱۰"</string>
- <string name="print_preview" msgid="8010217796057763343">"پیش‌نمایش چاپ"</string>
+ <string name="print_preview" msgid="8010217796057763343">"پیش‌نمای چاپ"</string>
<string name="install_for_print_preview" msgid="6366303997385509332">"‏نصب نمایشگر PDF برای پیش‌نمایش"</string>
<string name="printing_app_crashed" msgid="854477616686566398">"برنامه چاپ خراب شد"</string>
<string name="generating_print_job" msgid="3119608742651698916">"در حال ایجاد کار چاپ"</string>
diff --git a/packages/PrintSpooler/res/values-uz/strings.xml b/packages/PrintSpooler/res/values-uz/strings.xml
index d17bce7ae54e..ea0a6ea2f7b8 100644
--- a/packages/PrintSpooler/res/values-uz/strings.xml
+++ b/packages/PrintSpooler/res/values-uz/strings.xml
@@ -100,7 +100,7 @@
</string-array>
<string-array name="orientation_labels">
<item msgid="4061931020926489228">"Tik holat"</item>
- <item msgid="3199660090246166812">"Eniga"</item>
+ <item msgid="3199660090246166812">"Yotiq"</item>
</string-array>
<string name="print_write_error_message" msgid="5787642615179572543">"Faylga yozib bo‘lmadi"</string>
<string name="print_error_default_message" msgid="8602678405502922346">"Xatolik yuz berdi. Qaytadan urining."</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index f3b22d355b77..5fc311af26b2 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -139,7 +139,7 @@
<string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"‏قدرت سیگنال Wi‑Fi کامل است."</string>
<string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"شبکه باز"</string>
<string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"شبکه ایمن"</string>
- <string name="process_kernel_label" msgid="950292573930336765">"‏سیستم عامل Android"</string>
+ <string name="process_kernel_label" msgid="950292573930336765">"‏سیستم‌عامل Android"</string>
<string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"برنامه‌های حذف شده"</string>
<string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"برنامه‌ها و کاربران حذف شده"</string>
<string name="data_usage_ota" msgid="7984667793701597001">"به‌روزرسانی‌های سیستم"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index f219d248e641..8b92640e9996 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -37,7 +37,7 @@
<string name="wifi_no_internet" msgid="1774198889176926299">"Ինտերնետ կապ չկա"</string>
<string name="saved_network" msgid="7143698034077223645">"Ով է պահել՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Ավտոմատ կերպով կապակցվել է %1$s-ի միջոցով"</string>
- <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Ավտոմատ կերպով միացել է ցանցի վարկանիշի ծառայության մատակարարի միջոցով"</string>
+ <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Ավտոմատ միացել է ցանցերի վարկանիշի մատակարարի միջոցով"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Միացված է %1$s-ի միջոցով"</string>
<string name="connected_via_app" msgid="3532267661404276584">"Միացված է <xliff:g id="NAME">%1$s</xliff:g>-ի միջոցով"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Հասանելի է %1$s-ի միջոցով"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 83b72e925fe1..27f5dc9cc4d4 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -93,8 +93,8 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Sim-toegang"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Gehoorapparaten"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Verbonden met gehoorapparaten"</string>
+ <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hoortoestellen"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Verbonden met hoortoestellen"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Verbonden met audio van medium"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Verbonden met audio van telefoon"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Verbonden met server voor bestandsoverdracht"</string>
@@ -111,7 +111,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Gebruiken voor audio van telefoon"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Gebruiken voor bestandsoverdracht"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gebruiken voor invoer"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Gebruiken voor gehoorapparaten"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Gebruiken voor hoortoestellen"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Koppelen"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"KOPPELEN"</string>
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Annuleren"</string>
@@ -127,8 +127,8 @@
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Hoofdtelefoon"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Randapparaat voor invoer"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
- <string name="bluetooth_hearingaid_left_pairing_message" msgid="8561855779703533591">"Linker gehoorapparaat koppelen…"</string>
- <string name="bluetooth_hearingaid_right_pairing_message" msgid="2655347721696331048">"Rechter gehoorapparaat koppelen…"</string>
+ <string name="bluetooth_hearingaid_left_pairing_message" msgid="8561855779703533591">"Linker hoortoestel koppelen…"</string>
+ <string name="bluetooth_hearingaid_right_pairing_message" msgid="2655347721696331048">"Rechter hoortoestel koppelen…"</string>
<string name="bluetooth_hearingaid_left_battery_level" msgid="7375621694748104876">"Links: batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_hearingaid_right_battery_level" msgid="1850094448499089312">"Rechts: batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi: uitgeschakeld."</string>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 66be8dd68283..a29314817a8f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -860,9 +860,6 @@ class SettingsProtoDumpUtil {
p.end(intentFirewallToken);
dumpSetting(s, p,
- Settings.Global.JOB_SCHEDULER_CONSTANTS,
- GlobalSettingsProto.JOB_SCHEDULER_CONSTANTS);
- dumpSetting(s, p,
Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS,
GlobalSettingsProto.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 0ac3355c4952..f219aecfc9d9 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -309,7 +309,6 @@ public class SettingsBackupTest {
Settings.Global.INSTANT_APP_DEXOPT_ENABLED,
Settings.Global.INTENT_FIREWALL_UPDATE_CONTENT_URL,
Settings.Global.INTENT_FIREWALL_UPDATE_METADATA_URL,
- Settings.Global.JOB_SCHEDULER_CONSTANTS,
Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS,
Settings.Global.KEEP_PROFILE_IN_BACKGROUND,
Settings.Global.KERNEL_CPU_THREAD_READER,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 4ce9f5a9edc6..af008b996172 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -113,6 +113,7 @@
<uses-permission android:name="android.permission.SET_ORIENTATION" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.MONITOR_INPUT" />
+ <uses-permission android:name="android.permission.INPUT_CONSUMER" />
<!-- DreamManager -->
<uses-permission android:name="android.permission.READ_DREAM_STATE" />
diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md
index 68b9553749e7..148fabbbaf2c 100644
--- a/packages/SystemUI/README.md
+++ b/packages/SystemUI/README.md
@@ -88,11 +88,6 @@ activity. It provides this cached data to RecentsActivity when it is started.
Registers all the callbacks/listeners required to show the Volume dialog when
it should be shown.
-### [com.android.systemui.stackdivider.Divider](/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java)
-
-Shows the drag handle for the divider between two apps when in split screen
-mode.
-
### [com.android.systemui.status.phone.StatusBar](/packages/SystemUI/src/com/android/systemui/status/phone/StatusBar.java)
This shows the UI for the status bar and the notification shade it contains.
@@ -153,6 +148,10 @@ Draws decorations about the screen in software (e.g. rounded corners, cutouts).
Biometric UI.
+### [com.android.systemui.wmshell.WMShell](/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java)
+
+Delegates SysUI events to WM Shell controllers.
+
---
* [Plugins](/packages/SystemUI/docs/plugins.md)
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index b42d71abaa6d..df66bf5a1051 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -45,4 +45,5 @@
-keep class com.android.systemui.dagger.GlobalRootComponent { *; }
-keep class com.android.systemui.dagger.GlobalRootComponent$SysUIComponentImpl { *; }
--keep class com.android.systemui.dagger.Dagger** { *; } \ No newline at end of file
+-keep class com.android.systemui.dagger.Dagger** { *; }
+-keep class com.android.systemui.tv.Dagger** { *; } \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/drawable/face_auth_wallpaper.png b/packages/SystemUI/res-keyguard/drawable/face_auth_wallpaper.png
new file mode 100644
index 000000000000..b907f4eaf362
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/face_auth_wallpaper.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/bubble_stack_user_education.xml b/packages/SystemUI/res/layout/bubble_stack_user_education.xml
index 616403219bc6..fe1ed4b6f726 100644
--- a/packages/SystemUI/res/layout/bubble_stack_user_education.xml
+++ b/packages/SystemUI/res/layout/bubble_stack_user_education.xml
@@ -15,8 +15,8 @@
~ limitations under the License.
-->
<LinearLayout
+ android:id="@+id/stack_education_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/user_education_view"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingTop="48dp"
@@ -25,26 +25,29 @@
android:paddingEnd="16dp"
android:layout_marginEnd="24dp"
android:orientation="vertical"
- android:background="@drawable/bubble_stack_user_education_bg">
-
+ android:background="@drawable/bubble_stack_user_education_bg"
+ >
<TextView
- android:id="@+id/user_education_title"
+ android:id="@+id/stack_education_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
android:maxLines="2"
android:ellipsize="end"
+ android:gravity="start"
+ android:textAlignment="viewStart"
android:text="@string/bubbles_user_education_title"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/>
<TextView
- android:id="@+id/user_education_description"
+ android:id="@+id/stack_education_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
+ android:gravity="start"
+ android:textAlignment="viewStart"
android:text="@string/bubbles_user_education_description"
android:fontFamily="@*android:string/config_bodyFontFamily"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
-
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml b/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
index 213bb923db65..b51dc93dc373 100644
--- a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
+++ b/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
@@ -14,77 +14,77 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.bubbles.ManageEducationView
+
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:id="@+id/manage_education_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="true"
+ android:paddingTop="28dp"
+ android:paddingBottom="16dp"
+ android:paddingStart="@dimen/bubble_expanded_view_padding"
+ android:paddingEnd="48dp"
+ android:layout_marginEnd="24dp"
+ android:orientation="vertical"
+ android:background="@drawable/bubble_stack_user_education_bg"
>
- <LinearLayout
+
+ <TextView
+ android:id="@+id/user_education_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:id="@+id/manage_education_view"
- android:clickable="true"
- android:paddingTop="28dp"
+ android:paddingStart="16dp"
android:paddingBottom="16dp"
- android:paddingStart="@dimen/bubble_expanded_view_padding"
- android:paddingEnd="48dp"
- android:layout_marginEnd="24dp"
- android:orientation="vertical"
- android:background="@drawable/bubble_stack_user_education_bg"
- >
+ android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:gravity="start"
+ android:textAlignment="viewStart"
+ android:text="@string/bubbles_user_education_manage_title"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/>
- <TextView
- android:id="@+id/user_education_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingBottom="16dp"
- android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
- android:maxLines="2"
- android:ellipsize="end"
- android:text="@string/bubbles_user_education_manage_title"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/>
+ <TextView
+ android:id="@+id/user_education_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dp"
+ android:paddingBottom="24dp"
+ android:text="@string/bubbles_user_education_manage"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:gravity="start"
+ android:textAlignment="viewStart"
+ android:fontFamily="@*android:string/config_bodyFontFamily"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
- <TextView
- android:id="@+id/user_education_description"
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:id="@+id/button_layout"
+ android:orientation="horizontal" >
+
+ <com.android.systemui.statusbar.AlphaOptimizedButton
+ style="@android:style/Widget.Material.Button.Borderless"
+ android:id="@+id/manage"
+ android:layout_gravity="start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingBottom="24dp"
- android:text="@string/bubbles_user_education_manage"
- android:maxLines="2"
- android:ellipsize="end"
- android:fontFamily="@*android:string/config_bodyFontFamily"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
+ android:focusable="true"
+ android:clickable="false"
+ android:text="@string/manage_bubbles_text"
+ android:textColor="?attr/wallpaperTextColor"
+ />
- <LinearLayout
- android:layout_height="wrap_content"
+ <com.android.systemui.statusbar.AlphaOptimizedButton
+ style="@android:style/Widget.Material.Button.Borderless"
+ android:id="@+id/got_it"
+ android:layout_gravity="start"
android:layout_width="wrap_content"
- android:id="@+id/button_layout"
- android:orientation="horizontal" >
-
- <com.android.systemui.statusbar.AlphaOptimizedButton
- style="@android:style/Widget.Material.Button.Borderless"
- android:id="@+id/manage"
- android:layout_gravity="start"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:clickable="false"
- android:text="@string/manage_bubbles_text"
- android:textColor="?attr/wallpaperTextColor"
- />
-
- <com.android.systemui.statusbar.AlphaOptimizedButton
- style="@android:style/Widget.Material.Button.Borderless"
- android:id="@+id/got_it"
- android:layout_gravity="start"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:text="@string/bubbles_user_education_got_it"
- android:textColor="?attr/wallpaperTextColor"
- />
- </LinearLayout>
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:text="@string/bubbles_user_education_got_it"
+ android:textColor="?attr/wallpaperTextColor"
+ />
</LinearLayout>
-</com.android.systemui.bubbles.ManageEducationView>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index 2c4b937ce95b..fd89c0bf39dd 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -210,7 +210,7 @@
android:clickable="false"
android:focusable="false"
android:ellipsize="end"
- android:maxLines="3"
+ android:maxLines="4"
android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
</com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
diff --git a/packages/SystemUI/res/layout/partial_conversation_info.xml b/packages/SystemUI/res/layout/partial_conversation_info.xml
index 07951705664a..c353d089895c 100644
--- a/packages/SystemUI/res/layout/partial_conversation_info.xml
+++ b/packages/SystemUI/res/layout/partial_conversation_info.xml
@@ -128,6 +128,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
+ android:textDirection="locale"
style="@style/TextAppearance.NotificationImportanceChannelGroup" />
</LinearLayout>
</com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index bac915d854d8..316fa8aac5e6 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Hervat"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Kanselleer"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deel"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Vee uit"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skermopname is gekanselleer"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Skermopname is gestoor, tik om te sien"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Skermopname is uitgevee"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Kon nie skermopname uitvee nie"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Kon nie toestemmings kry nie"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Kon nie skermopname begin nie"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 43ab1d2d4fa1..e2a4dc6404d8 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ከቆመበት ቀጥል"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ይቅር"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"አጋራ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ሰርዝ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"የማያ ገጽ ቀረጻ ተሰርዟል"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"የማያ ገጽ ቀረጻ ተቀምጧል፣ ለመመልከት መታ ያድርጉ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"የማያ ገጽ ቀረጻ ተሰርዟል"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"የማያ ገጽ ቀረጻን መሰረዝ ላይ ስህተት"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ፈቃዶችን ማግኘት አልተቻለም"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"የማያ ገጽ ቀረጻን መጀመር ላይ ስህተት"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index c68d0887e425..b33c6c57f905 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"استئناف"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"إلغاء"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"مشاركة"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"حذف"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"تمّ إلغاء تسجيل الشاشة."</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"تمّ حفظ تسجيل الشاشة، انقر لعرضه."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"تمّ حذف تسجيل الشاشة."</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"حدث خطأ أثناء حذف تسجيل الشاشة."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"تعذّر الحصول على أذونات."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"حدث خطأ في بدء تسجيل الشاشة"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index d604fd47c4fd..5a3c659727d3 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ৰখোৱাৰ পৰা পুনৰ আৰম্ভ কৰক"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"বাতিল কৰক"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"শ্বেয়াৰ কৰক"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"মচক"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"স্ক্রীণ ৰেকৰ্ড কৰাটো বাতিল কৰা হ’ল"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"স্ক্রীণ ৰেকৰ্ডিং ছেভ কৰা হ’ল, চাবলৈ টিপক"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"স্ক্রীণ ৰেকৰ্ডিং মচা হ’ল"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"স্ক্রীণ ৰেকৰ্ডিং মচি থাকোঁতে কিবা আসোঁৱাহ হ’ল"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"অনুমতি পাব পৰা নগ\'ল"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"স্ক্রীন ৰেকৰ্ড কৰা আৰম্ভ কৰোঁতে আসোঁৱাহ হৈছে"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index b1df2522a513..4aa4bda6d35a 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Davam edin"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Ləğv edin"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Paylaşın"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Silin"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekranın video çəkimi ləğv edildi"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekranın video çəkimi yadda saxlanıldı. Baxmaq üçün klikləyin"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekranın video çəkimi silindi"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ekranın video çəkiminin silinməsi zamanı xəta baş verdi"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"İcazələr əldə edilmədi"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ekranın yazılması ilə bağlı xəta"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index f3c4c6b8487d..a9725f331856 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Nastavi"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Otkaži"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deli"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Izbriši"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snimanje ekrana je otkazano"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Snimak ekrana je sačuvan, dodirnite da biste pregledali"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Snimak ekrana je izbrisan"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Došlo je do problema pri brisanju snimka ekrana"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Preuzimanje dozvola nije uspelo"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Greška pri pokretanju snimanja ekrana"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 9c0eeb206e9e..b4c5eba9f77b 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Узнавіць"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Скасаваць"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Абагуліць"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Выдаліць"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Запіс экрана скасаваны"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Запіс экрана захаваны. Націсніце, каб прагледзець"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Запіс экрана выдалены"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Памылка выдалення запісу экрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не ўдалося атрымаць дазволы"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Памылка пачатку запісу экрана"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 3bf12ad06f1a..52e82869d575 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Възобновяване"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Отказ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Споделяне"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Изтриване"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Записването на екрана е анулирано"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Записът на екрана е запазен. Докоснете, за да го видите"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Записът на екрана е изтрит"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"При изтриването на записа на екрана възникна грешка"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Извличането на разрешенията не бе успешно."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"При стартирането на записа на екрана възникна грешка"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 5b7c953d5692..d0de9cf03b38 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"আবার চালু করুন"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"বাতিল করুন"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"শেয়ার করুন"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"মুছুন"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"স্ক্রিন রেকর্ডিং বাতিল করা হয়েছে"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"স্ক্রিন রেকর্ডিং সেভ করা হয়েছে, দেখতে ট্যাপ করুন"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"স্ক্রিন রেকর্ডিং মুছে ফেলা হয়েছে"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"স্ক্রিন রেকডিং মুছে ফেলার সময় সমস্যা হয়েছে"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"অনুমতি পাওয়া যায়নি"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"স্ক্রিন রেকর্ডিং শুরু করার সময় সমস্যা হয়েছে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 31f88c8fbd24..57b7945c7a8c 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Nastavi"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Otkaži"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Dijeli"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Izbriši"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snimanje ekrana je otkazano"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Snimak ekrana je sačuvan. Dodirnite za prikaz."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Snimak ekrana je izbrisan"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Greška prilikom brisanja snimka ekrana"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Dobijanje odobrenja nije uspjelo"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Greška pri pokretanju snimanja ekrana"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 753e25f13420..0489d18ff36b 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Reprèn"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel·la"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Comparteix"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Suprimeix"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"S\'ha cancel·lat la gravació de la pantalla"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"S\'ha desat la gravació de la pantalla; toca per mostrar"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"S\'ha suprimit la gravació de la pantalla"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"S\'ha produït un error en suprimir la gravació de la pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"No s\'han pogut obtenir els permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"S\'ha produït un error en iniciar la gravació de pantalla"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 039500d2a4f4..121a81db9ddf 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Obnovit"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Zrušit"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Sdílet"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Smazat"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Nahrávání obrazovky bylo zrušeno"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Záznam obrazovky byl uložen, zobrazíte jej klepnutím"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Záznam obrazovky byl smazán"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Při mazání záznamu obrazovky došlo k chybě"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nepodařilo se načíst oprávnění"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Při spouštění nahrávání obrazovky došlo k chybě"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 0c8a5b75c9e6..886369598f1c 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Genoptag"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuller"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Del"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Slet"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skærmoptagelsen er annulleret"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Skærmoptagelsen er gemt. Tryk for at se den."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Skærmoptagelsen er slettet"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Der opstod en fejl ved sletning af skærmoptagelsen"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Det lykkedes ikke et hente tilladelserne"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Skærmoptagelsen kunne ikke startes"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 1c4c7ab229f9..8d990c66ecdf 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Fortsetzen"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Abbrechen"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Teilen"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Löschen"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Bildschirmaufzeichnung abgebrochen"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Bildschirmaufzeichnung gespeichert, zum Ansehen tippen"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Bildschirmaufzeichnung gelöscht"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Fehler beim Löschen der Bildschirmaufzeichnung"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Berechtigungen nicht erhalten"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Fehler beim Start der Bildschirmaufzeichnung"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 07ff80706b33..4384749b6407 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Συνέχιση"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Ακύρωση"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Κοινοποίηση"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Διαγραφή"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Η εγγραφή οθόνης ακυρώθηκε"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Η εγγραφή οθόνης αποθηκεύτηκε. Πατήστε για προβολή."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Η εγγραφή οθόνης διαγράφηκε"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Παρουσιάστηκε σφάλμα κατά τη διαγραφή της εγγραφής οθόνης"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Η λήψη αδειών απέτυχε"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Σφάλμα κατά την έναρξη της εγγραφής οθόνης"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 0e22b583352c..8a7963a1f845 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Resume"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Screen recording deleted"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index acf087d51181..7b2b25a0e678 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Resume"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Screen recording deleted"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 0e22b583352c..8a7963a1f845 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Resume"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Screen recording deleted"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 0e22b583352c..8a7963a1f845 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Resume"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Screen recording deleted"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 4f4238a5eb45..15738f2512f4 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‎‎‎‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‏‏‎Resume‎‏‎‎‏‎"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‏‏‎‎Cancel‎‏‎‎‏‎"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‎‎Share‎‏‎‎‏‎"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‏‏‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎Delete‎‏‎‎‏‎"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‏‎‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‏‎‏‏‎‏‎Screen recording canceled‎‏‎‎‏‎"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‏‎‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎Screen recording saved, tap to view‎‏‎‎‏‎"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‏‎‎‎‏‏‎‏‎‎‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎Screen recording deleted‎‏‎‎‏‎"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‎‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‎‏‏‏‏‎‎‎‎‎‎‎‏‎‏‏‎‏‎‏‎‎‎Error deleting screen recording‎‏‎‎‏‎"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎Failed to get permissions‎‏‎‎‏‎"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‎‏‏‏‏‎‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‎‎Error starting screen recording‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 38fa52874512..aa81ab8efadd 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Reanudar"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Borrar"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Se canceló la grabación de pantalla"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Se guardó la grabación de pantalla; presiona para verla"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Se borró la grabación de pantalla"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error al borrar la grabación de pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Error al obtener permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error al iniciar la grabación de pantalla"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 10aa6cac7c2a..863857016388 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Seguir"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Eliminar"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Se ha cancelado la grabación de la pantalla"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Se ha guardado la grabación de la pantalla; toca para verla"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Se ha eliminado la grabación de la pantalla"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"No se ha podido eliminar la grabación de la pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"No se han podido obtener los permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"No se ha podido empezar a grabar la pantalla"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 9122ce5c4c0d..f5ffad255cf6 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Jätka"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Tühista"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Jaga"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Kustuta"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekraanikuva salvestamine on tühistatud"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekraanikuva salvestis on salvestatud, puudutage vaatamiseks"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekraanikuva salvestis on kustutatud"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Viga ekraanikuva salvestise kustutamisel"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Lubade hankimine ebaõnnestus"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Viga ekraanikuva salvestamise alustamisel"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 38b2103d7973..1d5ac1a15838 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Berrekin"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Utzi"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partekatu"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Ezabatu"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Utzi zaio pantaila grabatzeari"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Gorde da pantailaren grabaketa; sakatu ikusteko"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ezabatu da pantailaren grabaketa"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Errore bat gertatu da pantailaren grabaketa ezabatzean"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Ezin izan dira lortu baimenak"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Errore bat gertatu da pantaila grabatzen hastean"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d39d0c3d5027..55d8ab2566c6 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ازسرگیری"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"لغو"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"هم‌رسانی"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"حذف"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ضبط صفحه‌نمایش لغو شد"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ضبط صفحه‌نمایش ذخیره شد، برای مشاهده ضربه بزنید"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"فایل ضبط صفحه‌نمایش حذف شد"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"خطا در حذف فایل ضبط صفحه‌نمایش"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"مجوزها دریافت نشدند"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"خطا هنگام شروع ضبط صفحه‌نمایش"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 52e5e8cf29d6..f30c44b3ffba 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Jatka"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Peruuta"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Jaa"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Poista"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Näytön tallennus peruutettu"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Näyttötallenne tallennettu, katso napauttamalla"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Näyttötallenne poistettu"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Virhe poistettaessa näyttötallennetta"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Käyttöoikeuksien hakeminen epäonnistui."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Virhe näytön tallennuksen aloituksessa"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 4797f323b5d5..f6196dd63695 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Reprendre"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuler"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partager"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Supprimer"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"L\'enregistrement d\'écran a été annulé"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"L\'enregistrement d\'écran est terminé. Touchez ici pour l\'afficher."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"L\'enregistrement d\'écran a été supprimé"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Une erreur s\'est produite lors de la suppression de l\'enregistrement d\'écran"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Impossible d\'obtenir les autorisations"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Une erreur s\'est produite lors du démarrage de l\'enregistrement d\'écran"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index e5df728c34c6..0146ce4d9a59 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Reprendre"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuler"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partager"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Supprimer"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Enregistrement de l\'écran annulé"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Enregistrement de l\'écran enregistré. Appuyez pour afficher"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Enregistrement de l\'écran supprimé"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erreur lors de la suppression de l\'enregistrement de l\'écran"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Échec d\'obtention des autorisations"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Erreur lors du démarrage de l\'enregistrement de l\'écran"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 246fefd316db..fd4d3c6a4ad5 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Retomar"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Eliminar"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Cancelouse a gravación de pantalla"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Gardouse a gravación de pantalla; toca esta notificación para visualizala"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Eliminouse a gravación de pantalla"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Produciuse un erro ao eliminar a gravación de pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Produciuse un erro ao obter os permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Produciuse un erro ao iniciar a gravación da pantalla"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index beaacaa1c073..46f7a2bde43c 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ફરી શરૂ કરો"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"રદ કરો"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"શેર કરો"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ડિલીટ કરો"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"સ્ક્રીન રેકોર્ડિંગ રદ કર્યું"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"સ્ક્રીન રેકોર્ડિંગ સાચવ્યું, જોવા માટે ટૅપ કરો"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"સ્ક્રીન રેકોર્ડિંગ ડિલીટ કર્યું"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"સ્ક્રીન રેકોર્ડિંગ ડિલીટ કરવામાં ભૂલ આવી"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"પરવાનગીઓ મેળવવામાં નિષ્ફળ રહ્યાં"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"સ્ક્રીનને રેકૉર્ડ કરવાનું શરૂ કરવામાં ભૂલ"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index de4fc482a101..e4a6ed79848d 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"फिर से शुरू करें"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"रद्द करें"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"शेयर करें"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"मिटाएं"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"स्क्रीन रिकॉर्डिंग रद्द कर दी गई"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"स्क्रीन रिकॉर्डिंग सेव की गई, देखने के लिए टैप करें"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"स्क्रीन रिकॉर्डिंग मिटा दी गई"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"स्क्रीन रिकॉर्डिंग मिटाने में गड़बड़ी हुई"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"मंज़ूरी नहीं मिल सकी"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रीन को रिकॉर्ड करने में गड़बड़ी आ रही है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 7bf0b93b9bcb..a27b06694588 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Nastavi"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Odustani"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Dijeli"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Izbriši"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snimanje zaslona otkazano"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Snimanje zaslona spremljeno je, dodirnite da biste ga pregledali"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Snimanje zaslona izbrisano"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Pogreška prilikom brisanja snimanja zaslona"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Dohvaćanje dopuštenja nije uspjelo"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Pogreška prilikom pokretanja snimanja zaslona"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 875a05f71453..0d1f50acc1c7 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Folytatás"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Mégse"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Megosztás"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Törlés"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"A képernyő rögzítése megszakítva"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Képernyőfelvétel mentve, koppintson a megtekintéshez"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"A képernyőről készült felvétel törölve"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Hiba történt a képernyőről készült felvétel törlésekor"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nincs engedély"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Hiba a képernyőrögzítés indításakor"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 4cc406bf9af7..f9a10fa1578e 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Վերսկսել"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Չեղարկել"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Կիսվել"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Ջնջել"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Էկրանի տեսագրումը չեղարկվեց"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Էկրանի տեսագրությունը պահվեց։ Հպեք՝ դիտելու համար:"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Էկրանի տեսագրությունը ջնջվեց"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Չհաջողվեց ջնջել տեսագրությունը"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Չհաջողվեց ստանալ անհրաժեշտ թույլտվությունները"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Չհաջողվեց սկսել տեսագրումը"</string>
@@ -337,7 +335,7 @@
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"Էկրանը կողպված է ուղղաձիգ դիրքավորմամբ:"</string>
<string name="accessibility_rotation_lock_off_changed" msgid="5772498370935088261">"Էկրանն այժմ ավտոմատ կպտտվի:"</string>
<string name="accessibility_rotation_lock_on_landscape_changed" msgid="5785739044300729592">"Էկրանն այժմ կողպված է հորիզոնական դիրքում:"</string>
- <string name="accessibility_rotation_lock_on_portrait_changed" msgid="5580170829728987989">"Էկրանն այժմ կողպված է ուղղահայաց դիրքում:"</string>
+ <string name="accessibility_rotation_lock_on_portrait_changed" msgid="5580170829728987989">"Էկրանն այժմ կողպված է ուղղաձիգ դիրքում:"</string>
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
<string name="start_dreams" msgid="9131802557946276718">"Էկրանապահ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 5f7dce43925a..f65be90bb00e 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Lanjutkan"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Batal"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Bagikan"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Hapus"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Rekaman layar dibatalkan"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Rekaman layar disimpan, ketuk untuk melihat"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Rekaman layar dihapus"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error saat menghapus rekaman layar"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Gagal mendapatkan izin"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Terjadi error saat memulai perekaman layar"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index b5f6e57002df..66c91477c1e8 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Halda áfram"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Hætta við"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deila"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Eyða"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Hætt við skjáupptöku"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Skjáupptaka vistuð, ýttu til að skoða"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Skjáupptöku eytt"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Villa við að eyða skjáupptöku"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Ekki tókst að fá heimildir"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Villa við að hefja upptöku skjás"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index f4453b76bb61..b0e64a27f154 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Riprendi"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annulla"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Condividi"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"CANC"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Registrazione dello schermo annullata"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Registrazione dello schermo salvata. Tocca per visualizzarla."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Registrazione dello schermo eliminata"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Errore durante l\'eliminazione della registrazione dello schermo"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Impossibile ottenere le autorizzazioni"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Errore durante l\'avvio della registrazione dello schermo"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 161fedc7a41e..92fa09b81e39 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"המשך"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ביטול"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"שיתוף"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"מחיקה"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"הקלטת המסך בוטלה"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"הקלטת המסך נשמרה, יש להקיש כדי להציג"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"הקלטת המסך נמחקה"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"שגיאה במחיקת הקלטת המסך"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"קבלת ההרשאות נכשלה"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"שגיאה בהפעלה של הקלטת המסך"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index fa9c040b29a9..e427c8f950e5 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"再開"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"キャンセル"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"共有"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"削除"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"画面の録画をキャンセルしました"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"画面の録画を保存しました。タップで表示できます"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"画面の録画を削除しました"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"画面の録画の削除中にエラーが発生しました"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"権限を取得できませんでした"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"画面の録画中にエラーが発生しました"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index a3ddf70b5b25..b86bf8c32a75 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"გაგრძელება"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"გაუქმება"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"გაზიარება"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"წაშლა"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ეკრანის ჩაწერა გაუქმდა"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ეკრანის ჩანაწერი შენახულია, შეეხეთ სანახავად"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ეკრანის ჩანაწერი წაიშალა"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ეკრანის ჩანაწერის წაშლისას წარმოიშვა შეცდომა"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ნებართვების მიღება ვერ მოხერხდა"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ეკრანის ჩაწერის დაწყებისას წარმოიქმნა შეცდომა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 0d3f7f9f1973..1adaf2bc2755 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Жалғастыру"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Бас тарту"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Бөлісу"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Жою"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Экранды бейнеге жазудан бас тартылды"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Экран бейне жазбасы сақталды, көру үшін түртіңіз"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Экран бейне жазбасы жойылды"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Экран бейне жазбасын жою кезінде қате кетті"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Рұқсаттар алынбады"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Экрандағы бейнені жазу кезінде қате шықты."</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 5abd74000af5..961a37b3cd57 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"បន្ត"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"បោះបង់"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ចែករំលែក"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"លុប"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"បាន​បោះបង់​ការថត​សកម្មភាព​អេក្រង់"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"បានរក្សាទុក​ការថត​សកម្មភាព​អេក្រង់។ សូមចុច​ដើម្បី​មើល"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"បានលុប​ការថត​សកម្មភាព​អេក្រង់"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"មានបញ្ហា​ក្នុងការ​លុបការថត​សកម្មភាព​អេក្រង់"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"មិនអាច​ទទួលបាន​ការអនុញ្ញាត​ទេ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"មានបញ្ហា​ក្នុងការ​ចាប់ផ្ដើម​ថត​អេក្រង់"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 47f23856c7b0..7ec6a9f54a74 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ಮುಂದುವರಿಸಿ"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ರದ್ದುಮಾಡಿ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ಅಳಿಸಿ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅನ್ನು ರದ್ದುಮಾಡಲಾಗಿದೆ"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅನ್ನು ಉಳಿಸಲಾಗಿದೆ, ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅಳಿಸಲಾಗಿದೆ"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅಳಿಸುವಾಗ ದೋಷ ಕಂಡುಬಂದಿದೆ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ಅನುಮತಿಗಳನ್ನು ಪಡೆಯುವಲ್ಲಿ ವಿಫಲವಾಗಿದೆ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಪ್ರಾರಂಭಿಸುವಾಗ ದೋಷ ಕಂಡುಬಂದಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index beb7edade8e6..840a98e32e23 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"재개"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"취소"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"공유"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"삭제"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"화면 녹화가 취소되었습니다."</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"화면 녹화본이 저장되었습니다. 확인하려면 탭하세요."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"화면 녹화가 삭제되었습니다."</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"화면 녹화는 삭제하는 중에 오류가 발생했습니다."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"권한을 확보하지 못했습니다."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"화면 녹화 시작 중 오류 발생"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 4fbb09e56bbd..14ee566d305c 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Улантуу"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Жокко чыгаруу"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Бөлүшүү"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Ооба"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Экранды жаздыруу жокко чыгарылды"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Экранды жаздыруу сакталды, көрүү үчүн таптап коюңуз"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Экранды жаздыруу өчүрүлдү"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Экранды жаздырууну өчүрүүдө ката кетти"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Уруксаттар алынбай калды"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Экранды жаздырууну баштоодо ката кетти"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 6d7feabfed1a..553d0da2e295 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ສືບຕໍ່"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ຍົກເລີກ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ແບ່ງປັນ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ລຶບ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ຍົກເລີກການບັນທຶກໜ້າຈໍແລ້ວ"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ຈັດເກັບການບັນທຶກໜ້າຈໍ, ແຕະເພື່ອເບິ່ງ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ລຶບການບັນທຶກໜ້າຈໍອອກແລ້ວ"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ເກີດຄວາມຜິດພາດໃນການລຶບການບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ໂຫຼດສິດອະນຸຍາດບໍ່ສຳເລັດ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ເກີດຄວາມຜິດພາດໃນການບັນທຶກໜ້າຈໍ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 21217a06179f..28d6e6b35431 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Tęsti"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Atšaukti"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Bendrinti"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Ištrinti"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekrano įrašymas atšauktas"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekrano įrašas išsaugotas, palieskite ir peržiūrėkite"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekrano įrašas ištrintas"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ištrinant ekrano įrašą įvyko klaida"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nepavyko gauti leidimų"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Pradedant ekrano vaizdo įrašymą iškilo problema"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 4945dfa3f3db..223a57fdb640 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Atsākt"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Atcelt"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Kopīgot"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Dzēst"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekrāna ierakstīšana ir atcelta."</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekrāna ieraksts ir saglabāts. Pieskarieties, lai to skatītu."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekrāna ieraksts ir izdzēsts."</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Dzēšot ekrāna ierakstu, radās kļūda."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Neizdevās iegūt atļaujas."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Sākot ierakstīt ekrāna saturu, radās kļūda."</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 40d4698f7c21..a591031cabba 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Продолжи"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Откажи"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Сподели"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Избриши"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Снимањето екран е откажано"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Снимката од екранот е зачувана, допрете за да ја видите"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Снимката од екранот е избришана"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Грешка при бришењето на снимката од екранот"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не успеаја да се добијат дозволи"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Грешка при почетокот на снимањето на екранот"</string>
@@ -667,7 +665,7 @@
<string name="tuner_warning_title" msgid="7721976098452135267">"Забава за некои, но не за сите"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Адаптерот на УИ на системот ви дава дополнителни начини за дотерување и приспособување на корисничкиот интерфејс на Android. Овие експериментални функции можеби ќе се изменат, расипат или ќе исчезнат во следните изданија. Продолжете со претпазливост."</string>
<string name="tuner_persistent_warning" msgid="230466285569307806">"Овие експериментални функции можеби ќе се изменат, расипат или ќе исчезнат во следните изданија. Продолжете со претпазливост."</string>
- <string name="got_it" msgid="477119182261892069">"Разбрав"</string>
+ <string name="got_it" msgid="477119182261892069">"Сфатив"</string>
<string name="tuner_toast" msgid="3812684836514766951">"Честито! Го додадовте Адаптерот на УИ на системот на Поставки"</string>
<string name="remove_from_settings" msgid="633775561782209994">"Отстрани од поставки"</string>
<string name="remove_from_settings_prompt" msgid="551565437265615426">"Да се отстрани Адаптерот на УИ на системот од Поставки и да престанат да се користат сите негови функции?"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index c3bd65ef8e50..47d220df5bde 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"പുനരാരംഭിക്കുക"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"റദ്ദാക്കുക"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"പങ്കിടുക"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ഇല്ലാതാക്കുക"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"സ്ക്രീൻ റെക്കോർഡിംഗ് റദ്ദാക്കി"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"സ്ക്രീൻ റെക്കോർഡിംഗ് സംരക്ഷിച്ചു, കാണാൻ ടാപ്പ് ചെയ്യുക"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"സ്ക്രീൻ റെക്കോർഡിംഗ് ഇല്ലാതാക്കി"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"സ്ക്രീൻ റെക്കോർഡിംഗ് ഇല്ലാതാക്കുന്നതിൽ പിശക്"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"അനുമതികൾ ലഭിച്ചില്ല"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"സ്ക്രീൻ റെക്കോർഡിംഗ് ആരംഭിക്കുന്നതിൽ പിശക്"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 5f08f05ed9be..202f292503b0 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Үргэлжлүүлэх"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Цуцлах"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Хуваалцах"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Устгах"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Дэлгэцийн бичлэгийг цуцалсан"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Дэлгэцийн бичлэгийг хадгалсан. Харахын тулд товшино уу"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Дэлгэцийн бичлэгийг устгасан"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Дэлгэцийн бичлэгийг устгахад алдаа гарлаа"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Зөвшөөрөл авч чадсангүй"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Дэлгэцийн бичлэгийг эхлүүлэхэд алдаа гарлаа"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 6d525df2d05b..e4120726c66c 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"पुन्हा सुरू करा"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"रद्द करा"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"शेअर करा"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"हटवा"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"स्क्रीन रेकॉर्डिंग रद्द केले"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"स्क्रीन रेकॉर्डिंग सेव्ह केली, पाहण्यासाठी टॅप करा"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"स्क्रीन रेकॉर्डिंग हटवले"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"स्क्रीन रेकॉर्डिंग हटवताना एरर आली"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"परवानग्या मिळवता आल्या नाहीत"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रीन रेकॉर्डिंग सुरू करताना एरर आली"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 4f832e4c450d..d01ab8cb07b3 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Sambung semula"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Batal"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Kongsi"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Padam"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Rakaman skrin dibatalkan"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Rakaman skrin disimpan, ketik untuk melihat"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Rakaman skrin dipadamkan"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ralat semasa memadamkan rakaman skrin"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Gagal mendapatkan kebenaran"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ralat semasa memulakan rakaman skrin"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 150ed94eec38..83272f2a43c4 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ဆက်လုပ်ရန်"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"မလုပ်တော့"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"မျှဝေရန်"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ဖျက်ရန်"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ဖန်သားပြင် ရိုက်ကူးမှု ပယ်ဖျက်လိုက်ပါပြီ"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ဖန်သားပြင် ရိုက်ကူးမှု သိမ်းထားသည်၊ ကြည့်ရန် တို့ပါ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ဖန်သားပြင် ရိုက်ကူးမှု ဖျက်ပြီးပါပြီ"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ဖန်သားပြင် ရိုက်ကူးမှု ဖျက်ရာတွင် အမှားအယွင်းရှိနေသည်"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ခွင့်ပြုချက် မရယူနိုင်ပါ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ဖန်သားပြင် ရိုက်ကူးမှု စတင်ရာတွင် အမှားအယွင်းရှိနေသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 849c2e9e7381..01859ef5a13e 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Gjenoppta"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Avbryt"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Del"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Slett"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skjermopptak er avbrutt"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Skjermopptaket er lagret. Trykk for å se det"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Skjermopptaket er slettet"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Feil ved sletting av skjermopptaket"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Kunne ikke få tillatelser"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Feil ved start av skjermopptaket"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 2ac442ec0225..e548a968675c 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"जारी राख्नुहोस्"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"रद्द गर्नुहोस्"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"सेयर गर्नुहोस्"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"मेट्नुहोस्"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"स्क्रिन रेकर्ड गर्ने कार्य रद्द गरियो"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"स्क्रिन रेकर्डिङ सुरक्षित गरियो, हेर्न ट्याप गर्नुहोस्‌"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"स्क्रिनको रेकर्डिङ मेटाइयो"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"स्क्रिनको रेकर्डिङ मेट्ने क्रममा त्रुटि"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"अनुमति प्राप्त गर्न सकिएन"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रिन रेकर्ड गर्न थाल्ने क्रममा त्रुटि भयो"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index da0f42754acd..fa028c336594 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Hervatten"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuleren"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Delen"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Verwijderen"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Schermopname geannuleerd"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Schermopname opgeslagen, tik om te bekijken"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Schermopname verwijderd"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Fout bij verwijderen van schermopname"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Kan rechten niet ophalen"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Fout bij starten van schermopname"</string>
@@ -354,7 +352,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Invoer"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Gehoorapparaten"</string>
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Hoortoestellen"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Inschakelen..."</string>
<string name="quick_settings_brightness_label" msgid="680259653088849563">"Helderheid"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatisch draaien"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 029aa69b6fbf..4c6ef486436a 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ବାତିଲ୍‌ କରନ୍ତୁ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ସେୟାର୍‍ କରନ୍ତୁ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ଡିଲିଟ୍ କରନ୍ତୁ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ସ୍କ୍ରିନ୍‍ ରେକର୍ଡିଂ ବାତିଲ୍‌ କରିଦିଆଯାଇଛି"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ସ୍କ୍ରିନ୍‍ ରେକର୍ଡିଂ ସେଭ୍‍ ହୋଇଛି, ଦେଖିବାକୁ ଟାପ୍‍ କରନ୍ତୁ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ସ୍କ୍ରିନ୍‍ ରେକର୍ଡିଂ ଡିଲିଟ୍‍ କରିଦିଆଯାଇଛି"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ସ୍କ୍ରିନ୍‍ ରେକର୍ଡିଂ ଡିଲିଟ୍‍ କରିବାରେ ତ୍ରୁଟି"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ଅନୁମତି ପାଇବାରେ ଅସଫଳ ହେଲା।"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ଆରମ୍ଭ କରିବାରେ ତ୍ରୁଟି"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index ed5f40caf7d0..98583c0aedca 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ਰੱਦ ਕਰੋ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ਸਾਂਝਾ ਕਰੋ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ਮਿਟਾਓ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ਸਕ੍ਰੀਨ ਦੀ ਰਿਕਾਰਡਿੰਗ ਰੱਦ ਕੀਤੀ ਗਈ"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਰੱਖਿਅਤ ਕੀਤੀ ਗਈ, ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਮਿਟਾਇਆ ਗਿਆ"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਮਿਟਾਉਣ ਦੌਰਾਨ ਗੜਬੜ ਹੋਈ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ਇਜਾਜ਼ਤਾਂ ਪ੍ਰਾਪਤ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਵੇਲੇ ਗੜਬੜ ਹੋਈ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index ba30cedd9e39..4d5a2ae88949 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Wznów"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Anuluj"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Udostępnij"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Usuń"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Anulowano nagrywanie zawartości ekranu"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Zapisano nagranie zawartości ekranu – kliknij, by je obejrzeć"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Usunięto nagranie zawartości ekranu"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Błąd podczas usuwania nagrania zawartości ekranu"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nie udało się uzyskać uprawnień"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Błąd podczas rozpoczynania rejestracji zawartości ekranu"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 715b0e45faeb..ef5c9cee6ee4 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Retomar"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartilhar"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Excluir"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Gravação de tela cancelada"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Gravação de tela salva, toque para ver"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Gravação de tela excluída"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erro ao excluir a gravação de tela"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Não foi possível acessar as permissões"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Erro ao iniciar a gravação de tela"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 1a59de496c91..541f12c32e02 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Retomar"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partilhar"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Eliminar"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Gravação de ecrã cancelada."</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Gravação de ecrã guardada. Toque para ver."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Gravação de ecrã eliminada."</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erro ao eliminar a gravação de ecrã."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Falha ao obter as autorizações."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ocorreu um erro ao iniciar a gravação do ecrã."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 715b0e45faeb..ef5c9cee6ee4 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Retomar"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartilhar"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Excluir"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Gravação de tela cancelada"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Gravação de tela salva, toque para ver"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Gravação de tela excluída"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erro ao excluir a gravação de tela"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Não foi possível acessar as permissões"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Erro ao iniciar a gravação de tela"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index cf428a39d4a7..3e2373deb67d 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Reluați"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Anulați"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Trimiteți"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Ștergeți"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Înregistrarea ecranului a fost anulată"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Înregistrarea ecranului a fost salvată. Atingeți pentru vizualizare"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Înregistrarea ecranului a fost ștearsă."</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Eroare la ștergerea înregistrării ecranului"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nu s-au obținut permisiunile"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Eroare la începerea înregistrării ecranului"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index ba86e9501006..7747724eab80 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Возобновить"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Отмена"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Поделиться"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Удалить"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Запись видео с экрана отменена"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Запись видео с экрана сохранена. Чтобы открыть ее, нажмите на уведомление."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Запись видео с экрана удалена"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Не удалось удалить запись видео с экрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не удалось получить необходимые разрешения"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Не удалось начать запись видео с экрана."</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 1cd1ceb21c97..b8813f2ef53c 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"නැවත අරඹන්න"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"අවලංගු කරන්න"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"බෙදා ගන්න"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"මකන්න"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"තිර පටිගත කිරීම අවලංගු කරන ලදී"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"තිර පටිගත කිරීම සුරකින ලදී, බැලීමට තට්ටු කරන්න"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"තිර පටිගත කිරීම මකන ලදී"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"තිර පටිගත කිරීම මැකීමේ දෝෂයකි"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"අවසර ලබා ගැනීමට අසමත් විය"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"තිර පටිගත කිරීම ආරම්භ කිරීමේ දෝෂයකි"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 75486073fd5e..0f9cb5f4616c 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Obnoviť"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Zrušiť"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Zdieľať"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Odstrániť"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Záznam obrazovky bol zrušený"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Záznam obrazovky bol uložený, zobrazíte ho klepnutím"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Záznam obrazovky bol odstránený"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Pri odstraňovaní záznamu obrazovky sa vyskytla chyba"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nepodarilo sa získať povolenia"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Pri spustení nahrávania obrazovky sa vyskytla chyba"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 07ad8c1ca99e..18db332b63ec 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Nadaljuj"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Prekliči"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deli"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Izbriši"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snemanje zaslona je preklicano"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Videoposnetek zaslona je shranjen, dotaknite se za ogled"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Videoposnetek zaslona je izbrisan"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Napaka pri brisanju videoposnetka zaslona"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Dovoljenj ni bilo mogoče pridobiti"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Napaka pri začenjanju snemanja zaslona"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index b92744d7f087..57ab1c384ca9 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -108,15 +108,13 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Vazhdo"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Anulo"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Ndaj"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Fshi"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Regjistrimi i ekranit u anulua"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Regjistrimi i ekranit u ruajt, trokit për ta parë"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Regjistrimi i ekranit u fshi"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Gabim gjatë fshirjes së regjistrimit të ekranit"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Marrja e lejeve dështoi"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Gabim gjatë nisjes së regjistrimit të ekranit"</string>
<string name="usb_preference_title" msgid="1439924437558480718">"Opsionet e transferimit të dosjeve të USB-së"</string>
- <string name="use_mtp_button_title" msgid="5036082897886518086">"Lidh si një lexues \"media\" (MTP)"</string>
+ <string name="use_mtp_button_title" msgid="5036082897886518086">"Lidh si një luajtës të medias (MTP)"</string>
<string name="use_ptp_button_title" msgid="7676427598943446826">"Montoje si kamerë (PTP)"</string>
<string name="installer_cd_button_title" msgid="5499998592841984743">"Instalo \"Transferimi i skedarëve të Android\" për Mac"</string>
<string name="accessibility_back" msgid="6530104400086152611">"Prapa"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index f57d92bb911e..ec763f675d4c 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Настави"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Откажи"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Дели"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Избриши"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Снимање екрана је отказано"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Снимак екрана је сачуван, додирните да бисте прегледали"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Снимак екрана је избрисан"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Дошло је до проблема при брисању снимка екрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Преузимање дозвола није успело"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Грешка при покретању снимања екрана"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 876e3377171c..a0a563d81d46 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Återuppta"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Avbryt"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Dela"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Radera"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skärminspelningen har avbrutits"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Skärminspelningen har sparats, tryck här om du vill titta på den"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Skärminspelningen har raderats"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Det gick inte att radera skärminspelningen"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Behörighet saknas"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Det gick inte att starta skärminspelningen"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 25e349367b52..7e264a4a312a 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Endelea"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Ghairi"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Shiriki"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Futa"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Imeghairi mchakato wa kurekodi skrini"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Imehifadhi rekodi ya skrini, gusa ili uangalie"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Imefuta rekodi ya skrini"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Hitilafu imetokea wakati wa kufuta rekodi ya skrini"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Imeshindwa kupata ruhusa"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Hitilafu imetokea wakati wa kuanza kurekodi skrini"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 19e67db62de8..e0f20ceea353 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"மீண்டும் தொடங்கு"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ரத்துசெய்"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"பகிர்"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"நீக்கு"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"திரை ரெக்கார்டிங் ரத்துசெய்யப்பட்டது"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"திரை ரெக்கார்டிங் சேமிக்கப்பட்டது, பார்க்கத் தட்டவும்"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"திரை ரெக்கார்டிங் நீக்கப்பட்டது"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"திரை ரெக்கார்டிங்கை நீக்குவதில் பிழை"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"அனுமதிகளைப் பெற இயலவில்லை"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ஸ்கிரீன் ரெக்கார்டிங்கைத் தொடங்குவதில் பிழை"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 34ff9b102da0..3e94b72b02fe 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"కొనసాగించు"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"రద్దు చేయి"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"షేర్ చేయి"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"తొలగించు"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"స్క్రీన్ రికార్డ్ రద్దు చేయబడింది"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"స్క్రీన్ రికార్డింగ్ సేవ్ చేయబడింది, చూడటం కోసం నొక్కండి"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"స్క్రీన్ రికార్డింగ్ తొలగించబడింది"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"స్క్రీన్ రికార్డింగ్‌ని తొలగిస్తున్నప్పుడు ఎర్రర్ ఏర్పడింది"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"అనుమతులను పొందడం విఫలమైంది"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"స్క్రీన్ రికార్డింగ్ ప్రారంభించడంలో ఎర్రర్ ఏర్పడింది"</string>
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index 7b1479acc35e..b2d057b4bcd8 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -28,7 +28,6 @@
<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.stackdivider.Divider</item>
<item>com.android.systemui.statusbar.tv.TvStatusBar</item>
<item>com.android.systemui.usb.StorageNotification</item>
<item>com.android.systemui.power.PowerUI</item>
@@ -42,6 +41,7 @@
<item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
<item>com.android.systemui.toast.ToastUI</item>
<item>com.android.systemui.onehanded.OneHandedUI</item>
+ <item>com.android.systemui.wmshell.WMShell</item>
</string-array>
<!-- Show a separate icon for low and high volume on the volume dialog -->
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index d37be57e0136..088b62421b92 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ทำต่อ"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ยกเลิก"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"แชร์"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ลบ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ยกเลิกการบันทึกหน้าจอแล้ว"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"บันทึกการบันทึกหน้าจอแล้ว แตะเพื่อดู"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ลบการบันทึกหน้าจอแล้ว"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"เกิดข้อผิดพลาดในการลบการบันทึกหน้าจอ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ขอสิทธิ์ไม่สำเร็จ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"เกิดข้อผิดพลาดขณะเริ่มบันทึกหน้าจอ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index af474c761fc5..e787b17417bb 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Ituloy"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Kanselahin"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Ibahagi"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"I-delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Kinansela ang pag-record ng screen"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Na-save ang pag-record ng screen, i-tap para tingnan"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Na-delete ang pag-record ng screen"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error sa pag-delete sa pag-record ng screen"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Hindi nakuha ang mga pahintulot"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Nagkaroon ng error sa pagsisimula ng pag-record ng screen"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index ee494a25e366..e33944517393 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Devam ettir"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"İptal"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Paylaş"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Sil"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekran kaydı iptal edildi"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekran kaydı tamamlandı, görüntülemek için dokunun"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekran kaydı silindi"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ekran kaydı silinirken hata oluştu"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"İzinler alınamadı"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ekran kaydı başlatılırken hata oluştu"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index c444c47d1441..f5419f1d1290 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Відновити"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Скасувати"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Поділитися"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Видалити"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Запис екрана скасовано"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Запис екрана збережено. Натисніть, щоб переглянути"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Запис екрана видалено"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Не вдалося видалити запис екрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не вдалось отримати дозволи"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Не вдалося почати запис екрана"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 729ed5a3ac51..2abf3500ff4a 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"دوبارہ شروع کریں"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"منسوخ کریں"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"اشتراک کریں"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"حذف کریں"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"اسکرین ریکارڈنگ منسوخ ہو گئی"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"اسکرین ریکارڈنگ محفوظ ہو گئی، دیکھنے کیلئے تھپتھپائیں"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"اسکرین ریکارڈنگ حذف ہو گئی"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"اسکرین ریکارڈنگ کو حذف کرنے میں خرابی"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"اجازتیں حاصل کرنے میں ناکامی"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"اسکرین ریکارڈنگ شروع کرنے میں خرابی"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index cf1da7508052..61b10a4ed24c 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Davom etish"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Bekor qilish"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Ulashish"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"O‘chirish"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekrandan yozib olish bekor qilindi"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekrandan yozib olingan video saqlandi. Uni ochish uchun bildirishnomani bosing."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekrandan yozib olingan video o‘chirib tashlandi"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ekrandan yozib olingan vi olib tashlanmadi"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Zarur ruxsatlar olinmadi"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ekranni yozib olish boshlanmadi"</string>
@@ -362,7 +360,7 @@
<string name="accessibility_quick_settings_rotation_value" msgid="2916484894750819251">"<xliff:g id="ID_1">%s</xliff:g> rejimi"</string>
<string name="quick_settings_rotation_locked_label" msgid="4420863550666310319">"Aylanmaydigan qilingan"</string>
<string name="quick_settings_rotation_locked_portrait_label" msgid="1194988975270484482">"Tik holat"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="2000295772687238645">"Eniga"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="2000295772687238645">"Yotiq"</string>
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Kiritish usuli"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Joylashuv"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Joylashuvni aniqlash xizmati yoqilmagan"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 5794bdf3c8eb..6107270f10c5 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Tiếp tục"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Hủy"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Chia sẻ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Xóa"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Đã hủy bản ghi màn hình"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Đã lưu bản ghi màn hình, nhấn để xem"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Đã xóa bản ghi màn hình"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Lỗi khi xóa bản ghi màn hình"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Không được cấp đủ quyền"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Lỗi khi bắt đầu ghi màn hình"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 41c132c9faf6..ffd19956f471 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"继续"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"取消"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"分享"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"删除"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"已取消录制屏幕"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"屏幕录制内容已保存,点按即可查看"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"已删除屏幕录制内容"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"删除屏幕录制内容时出错"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"无法获取权限"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"启动屏幕录制时出错"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index b2e1b90de007..1575427f155b 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"繼續"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"取消"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"分享"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"刪除"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"已取消錄影畫面"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"已儲存錄影畫面,輕按即可查看"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"已刪除錄影畫面"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"刪除錄影畫面時發生錯誤"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"無法獲得權限"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"開始錄影畫面時發生錯誤"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 346b1239cf0f..bbd83551c0f9 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"繼續"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"取消"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"分享"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"刪除"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"已取消錄製螢幕畫面"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"已儲存螢幕畫面錄製內容,輕觸即可查看"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"已刪除螢幕畫面錄製內容"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"刪除螢幕畫面錄製內容時發生錯誤"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"無法取得權限"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"開始錄製螢幕畫面時發生錯誤"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 5abce7fb4415..63b4c613a06a 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Qalisa kabusha"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Khansela"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Yabelana"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Susa"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ukurekhoda isikrini kukhanseliwe"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ukurekhoda isikrini kulondoloziwe, thepha ukuze ubuke"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ukurekhoda isikrini kususiwe"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Iphutha lokususa ukurekhoda isikrini"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Yehlulekile ukuthola izimvume"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Iphutha lokuqala ukurekhoda isikrini"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index ce1ca5ad1723..130bb4fc90b9 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -301,7 +301,6 @@
<item>com.android.systemui.keyguard.KeyguardViewMediator</item>
<item>com.android.systemui.recents.Recents</item>
<item>com.android.systemui.volume.VolumeUI</item>
- <item>com.android.systemui.stackdivider.Divider</item>
<item>com.android.systemui.statusbar.phone.StatusBar</item>
<item>com.android.systemui.usb.StorageNotification</item>
<item>com.android.systemui.power.PowerUI</item>
@@ -323,6 +322,7 @@
<item>com.android.systemui.accessibility.SystemActions</item>
<item>com.android.systemui.toast.ToastUI</item>
<item>com.android.systemui.onehanded.OneHandedUI</item>
+ <item>com.android.systemui.wmshell.WMShell</item>
</string-array>
<!-- QS tile shape store width. negative implies fill configuration instead of stroke-->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 765a9422585a..d12f0103238d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1342,7 +1342,7 @@
<dimen name="controls_app_divider_height">2dp</dimen>
<dimen name="controls_app_divider_side_margin">32dp</dimen>
- <dimen name="controls_card_margin">2dp</dimen>
+ <dimen name="controls_card_margin">@dimen/control_base_item_margin</dimen>
<item name="control_card_elevation" type="dimen" format="float">15</item>
<dimen name="controls_dialog_padding">32dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 823c1ff2fdd0..bfa7532349aa 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -278,14 +278,10 @@
<string name="screenrecord_cancel_label">Cancel</string>
<!-- Label for notification action to share screen recording [CHAR LIMIT=35] -->
<string name="screenrecord_share_label">Share</string>
- <!-- Label for notification action to delete a screen recording file [CHAR LIMIT=35] -->
- <string name="screenrecord_delete_label">Delete</string>
<!-- A toast message shown after successfully canceling a screen recording [CHAR LIMIT=NONE] -->
<string name="screenrecord_cancel_success">Screen recording canceled</string>
<!-- Notification text shown after saving a screen recording to prompt the user to view it [CHAR LIMIT=100] -->
<string name="screenrecord_save_message">Screen recording saved, tap to view</string>
- <!-- A toast message shown after successfully deleting a screen recording [CHAR LIMIT=NONE] -->
- <string name="screenrecord_delete_description">Screen recording deleted</string>
<!-- A toast message shown when there is an error deleting a screen recording [CHAR LIMIT=NONE] -->
<string name="screenrecord_delete_error">Error deleting screen recording</string>
<!-- A toast message shown when the screen recording cannot be started due to insufficient permissions [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 748a9c9448c5..27809b50d746 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -65,7 +65,6 @@ import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -324,7 +323,6 @@ public class Dependency {
@Inject Lazy<DisplayImeController> mDisplayImeController;
@Inject Lazy<RecordingController> mRecordingController;
@Inject Lazy<ProtoTracer> mProtoTracer;
- @Inject Lazy<Divider> mDivider;
@Inject
public Dependency() {
@@ -521,7 +519,6 @@ public class Dependency {
mProviders.put(AutoHideController.class, mAutoHideController::get);
mProviders.put(RecordingController.class, mRecordingController::get);
- mProviders.put(Divider.class, mDivider::get);
Dependency.setInstance(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 59af458e2402..17b840cc7a20 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -162,8 +162,8 @@ public class ExpandHelper implements Gefingerpoken {
*
* @param context application context
* @param callback the container that holds the items to be manipulated
- * @param small the smallest allowable size for the manuipulated items.
- * @param large the largest allowable size for the manuipulated items.
+ * @param small the smallest allowable size for the manipulated items.
+ * @param large the largest allowable size for the manipulated items.
*/
public ExpandHelper(Context context, Callback callback, int small, int large) {
mSmallSize = small;
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index d17ca4041b31..47066a05b9b8 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -22,7 +22,6 @@ import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.NonNull;
-import android.content.Context;
import android.content.res.Resources;
import android.graphics.RectF;
import android.os.Handler;
@@ -115,24 +114,24 @@ public class SwipeHelper implements Gefingerpoken {
private final ArrayMap<View, Animator> mDismissPendingMap = new ArrayMap<>();
public SwipeHelper(
- int swipeDirection, Callback callback, Context context, FalsingManager falsingManager) {
+ int swipeDirection, Callback callback, Resources resources,
+ ViewConfiguration viewConfiguration, FalsingManager falsingManager) {
mCallback = callback;
mHandler = new Handler();
mSwipeDirection = swipeDirection;
mVelocityTracker = VelocityTracker.obtain();
- final ViewConfiguration configuration = ViewConfiguration.get(context);
- mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
- mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
+ mPagingTouchSlop = viewConfiguration.getScaledPagingTouchSlop();
+ mSlopMultiplier = viewConfiguration.getScaledAmbiguousGestureMultiplier();
// Extra long-press!
mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f);
- Resources res = context.getResources();
- mDensityScale = res.getDisplayMetrics().density;
- mFalsingThreshold = res.getDimensionPixelSize(R.dimen.swipe_helper_falsing_threshold);
- mFadeDependingOnAmountSwiped = res.getBoolean(R.bool.config_fadeDependingOnAmountSwiped);
+ mDensityScale = resources.getDisplayMetrics().density;
+ mFalsingThreshold = resources.getDimensionPixelSize(R.dimen.swipe_helper_falsing_threshold);
+ mFadeDependingOnAmountSwiped = resources.getBoolean(
+ R.bool.config_fadeDependingOnAmountSwiped);
mFalsingManager = falsingManager;
- mFlingAnimationUtils = new FlingAnimationUtils(res.getDisplayMetrics(),
+ mFlingAnimationUtils = new FlingAnimationUtils(resources.getDisplayMetrics(),
getMaxEscapeAnimDuration() / 1000f);
}
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index eeb3b28357d7..a3339f6fc051 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -19,6 +19,7 @@ package com.android.systemui.appops;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.location.LocationManager;
import android.media.AudioManager;
import android.media.AudioRecordingConfiguration;
import android.os.Handler;
@@ -66,6 +67,13 @@ public class AppOpsControllerImpl implements AppOpsController,
private final AppOpsManager mAppOps;
private final AudioManager mAudioManager;
+ private final LocationManager mLocationManager;
+
+ // mLocationProviderPackages are cached and updated only occasionally
+ private static final long LOCATION_PROVIDER_UPDATE_FREQUENCY_MS = 30000;
+ private long mLastLocationProviderPackageUpdate;
+ private List<String> mLocationProviderPackages;
+
private H mBGHandler;
private final List<AppOpsController.Callback> mCallbacks = new ArrayList<>();
private final SparseArray<Set<Callback>> mCallbacksByCode = new SparseArray<>();
@@ -83,8 +91,10 @@ public class AppOpsControllerImpl implements AppOpsController,
protected static final int[] OPS = new int[] {
AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION,
AppOpsManager.OP_CAMERA,
+ AppOpsManager.OP_PHONE_CALL_CAMERA,
AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
AppOpsManager.OP_RECORD_AUDIO,
+ AppOpsManager.OP_PHONE_CALL_MICROPHONE,
AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION
};
@@ -105,6 +115,7 @@ public class AppOpsControllerImpl implements AppOpsController,
mCallbacksByCode.put(OPS[i], new ArraySet<>());
}
mAudioManager = audioManager;
+ mLocationManager = context.getSystemService(LocationManager.class);
dumpManager.registerDumpable(TAG, this);
}
@@ -288,6 +299,26 @@ public class AppOpsControllerImpl implements AppOpsController,
return isUserVisible(item.getCode(), item.getUid(), item.getPackageName());
}
+ /**
+ * Checks if a package is the current location provider.
+ *
+ * <p>Data is cached to avoid too many calls into system server
+ *
+ * @param packageName The package that might be the location provider
+ *
+ * @return {@code true} iff the package is the location provider.
+ */
+ private boolean isLocationProvider(String packageName) {
+ long now = System.currentTimeMillis();
+
+ if (mLastLocationProviderPackageUpdate + LOCATION_PROVIDER_UPDATE_FREQUENCY_MS < now) {
+ mLastLocationProviderPackageUpdate = now;
+ mLocationProviderPackages = mLocationManager.getProviderPackages(
+ LocationManager.FUSED_PROVIDER);
+ }
+
+ return mLocationProviderPackages.contains(packageName);
+ }
/**
* Does the app-op, uid and package name, refer to an operation that should be shown to the
@@ -303,7 +334,13 @@ public class AppOpsControllerImpl implements AppOpsController,
// does not correspond to a platform permission
// which may be user sensitive, so for now always show it to the user.
if (appOpCode == AppOpsManager.OP_SYSTEM_ALERT_WINDOW
- || appOpCode == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) {
+ || appOpCode == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION
+ || appOpCode == AppOpsManager.OP_PHONE_CALL_CAMERA
+ || appOpCode == AppOpsManager.OP_PHONE_CALL_MICROPHONE) {
+ return true;
+ }
+
+ if (appOpCode == AppOpsManager.OP_CAMERA && isLocationProvider(packageName)) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java
index d4e6506bd9a0..0892612d1825 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java
@@ -111,7 +111,7 @@ public class AuthCredentialPasswordView extends AuthCredentialView
// VerifyCredentialResponse so that we can request a Gatekeeper HAT with the
// Gatekeeper Password and operationId.
mPendingLockCheck = LockPatternChecker.verifyCredential(mLockPatternUtils,
- password, mEffectiveUserId, LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW,
+ password, mEffectiveUserId, LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE,
this::onCredentialVerified);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java
index ad89ae82f637..ab8162f9464d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java
@@ -75,7 +75,7 @@ public class AuthCredentialPatternView extends AuthCredentialView {
mLockPatternUtils,
credential,
mEffectiveUserId,
- LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW,
+ LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE,
this::onPatternVerified);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
index a8f6f85201f6..b44ff294b792 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
@@ -292,10 +292,12 @@ public abstract class AuthCredentialView extends LinearLayout {
// The response passed into this method contains the Gatekeeper Password. We still
// have to request Gatekeeper to create a Hardware Auth Token with the
// Gatekeeper Password and Challenge (keystore operationId in this case)
- final VerifyCredentialResponse gkResponse = mLockPatternUtils.verifyGatekeeperPassword(
- response.getGatekeeperPw(), mOperationId, mEffectiveUserId);
+ final long pwHandle = response.getGatekeeperPasswordHandle();
+ final VerifyCredentialResponse gkResponse = mLockPatternUtils
+ .verifyGatekeeperPasswordHandle(pwHandle, mOperationId, mEffectiveUserId);
mCallback.onCredentialMatched(gkResponse.getGatekeeperHAT());
+ mLockPatternUtils.removeGatekeeperPasswordHandle(pwHandle);
} else {
if (timeoutMs > 0) {
mHandler.removeCallbacks(mClearErrorRunnable);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index ec9644af7013..64df2b99ee22 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -19,11 +19,7 @@ package com.android.systemui.bubbles;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_EDUCATION;
-import static com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION;
import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW;
-import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_USER_EDUCATION;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -38,7 +34,6 @@ import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Outline;
@@ -54,7 +49,6 @@ import android.provider.Settings;
import android.util.Log;
import android.view.Choreographer;
import android.view.DisplayCutout;
-import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceControl;
@@ -70,10 +64,8 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.LinearLayout;
import android.widget.TextView;
-import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.dynamicanimation.animation.DynamicAnimation;
@@ -82,7 +74,6 @@ import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Interpolators;
import com.android.systemui.Prefs;
import com.android.systemui.R;
@@ -115,10 +106,6 @@ public class BubbleStackView extends FrameLayout
implements ViewTreeObserver.OnComputeInternalInsetsListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleStackView" : TAG_BUBBLES;
- /** Animation durations for bubble stack user education views. **/
- static final int ANIMATE_STACK_USER_EDUCATION_DURATION = 200;
- private static final int ANIMATE_STACK_USER_EDUCATION_DURATION_SHORT = 40;
-
/** How far the flyout needs to be dragged before it's dismissed regardless of velocity. */
static final float FLYOUT_DRAG_PERCENT_DISMISS = 0.25f;
@@ -556,7 +543,7 @@ public class BubbleStackView extends FrameLayout
// Otherwise, we either tapped the stack (which means we're collapsed
// and should expand) or the currently selected bubble (we're expanded
// and should collapse).
- if (!maybeShowStackUserEducation()) {
+ if (!maybeShowStackEdu()) {
mBubbleData.setExpanded(!mBubbleData.isExpanded());
}
}
@@ -582,7 +569,9 @@ public class BubbleStackView extends FrameLayout
}
if (mBubbleData.isExpanded()) {
- maybeShowManageEducation(false /* show */);
+ if (mManageEduView != null) {
+ mManageEduView.hide(false /* show */);
+ }
// If we're expanded, tell the animation controller to prepare to drag this bubble,
// dispatching to the individual bubble magnet listener.
@@ -637,7 +626,9 @@ public class BubbleStackView extends FrameLayout
mExpandedAnimationController.dragBubbleOut(
v, viewInitialX + dx, viewInitialY + dy);
} else {
- hideStackUserEducation(false /* fromExpansion */);
+ if (mStackEduView != null) {
+ mStackEduView.hide(false /* fromExpansion */);
+ }
mStackAnimationController.moveStackFromTouch(
viewInitialX + dx, viewInitialY + dy);
}
@@ -684,7 +675,7 @@ public class BubbleStackView extends FrameLayout
private OnClickListener mFlyoutClickListener = new OnClickListener() {
@Override
public void onClick(View view) {
- if (maybeShowStackUserEducation()) {
+ if (maybeShowStackEdu()) {
// If we're showing user education, don't open the bubble show the education first
mBubbleToExpandAfterFlyoutCollapse = null;
} else {
@@ -728,7 +719,7 @@ public class BubbleStackView extends FrameLayout
mFlyout.removeCallbacks(mHideFlyout);
animateFlyoutCollapsed(shouldDismiss, velX);
- maybeShowStackUserEducation();
+ maybeShowStackEdu();
}
};
@@ -737,14 +728,8 @@ public class BubbleStackView extends FrameLayout
@Nullable
private BubbleOverflow mBubbleOverflow;
-
- private boolean mShouldShowUserEducation;
- private boolean mAnimatingEducationAway;
- private View mUserEducationView;
-
- private boolean mShouldShowManageEducation;
- private ManageEducationView mManageEducationView;
- private boolean mAnimatingManageEducationAway;
+ private StackEducationView mStackEduView;
+ private ManageEducationView mManageEduView;
private ViewGroup mManageMenu;
private ImageView mManageSettingsIcon;
@@ -805,8 +790,6 @@ public class BubbleStackView extends FrameLayout
onBubbleAnimatedOut);
mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER;
- setUpUserEducation();
-
// Force LTR by default since most of the Bubbles UI is positioned manually by the user, or
// is centered. It greatly simplifies translation positioning/animations. Views that will
// actually lay out differently in RTL, such as the flyout and expanded view, will set their
@@ -819,6 +802,8 @@ public class BubbleStackView extends FrameLayout
mBubbleContainer.setClipChildren(false);
addView(mBubbleContainer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ updateUserEdu();
+
mExpandedViewContainer = new FrameLayout(context);
mExpandedViewContainer.setElevation(elevation);
mExpandedViewContainer.setClipChildren(false);
@@ -1092,48 +1077,66 @@ public class BubbleStackView extends FrameLayout
addView(mManageMenu);
}
- private void setUpUserEducation() {
- if (mUserEducationView != null) {
- removeView(mUserEducationView);
- }
- mShouldShowUserEducation = shouldShowBubblesEducation();
- if (DEBUG_USER_EDUCATION) {
- Log.d(TAG, "shouldShowUserEducation: " + mShouldShowUserEducation);
+ /**
+ * Whether the educational view should show for the expanded view "manage" menu.
+ */
+ private boolean shouldShowManageEdu() {
+ final boolean seen = Prefs.getBoolean(mContext,
+ Prefs.Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION, false /* default */);
+ final boolean shouldShow = (!seen || BubbleDebugConfig.forceShowUserEducation(mContext))
+ && mExpandedBubble != null;
+ if (BubbleDebugConfig.DEBUG_USER_EDUCATION) {
+ Log.d(TAG, "Show manage edu: " + shouldShow);
}
- if (mShouldShowUserEducation) {
- mUserEducationView = mInflater.inflate(R.layout.bubble_stack_user_education, this,
- false /* attachToRoot */);
- mUserEducationView.setVisibility(GONE);
-
- final TypedArray ta = mContext.obtainStyledAttributes(
- new int[] {android.R.attr.colorAccent,
- android.R.attr.textColorPrimaryInverse});
- final int bgColor = ta.getColor(0, Color.BLACK);
- int textColor = ta.getColor(1, Color.WHITE);
- ta.recycle();
- textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, true);
+ return shouldShow;
+ }
- TextView title = mUserEducationView.findViewById(R.id.user_education_title);
- TextView description = mUserEducationView.findViewById(R.id.user_education_description);
- title.setTextColor(textColor);
- description.setTextColor(textColor);
+ private void maybeShowManageEdu() {
+ if (!shouldShowManageEdu()) {
+ return;
+ }
+ if (mManageEduView == null) {
+ mManageEduView = new ManageEducationView(mContext);
+ addView(mManageEduView);
+ }
+ mManageEduView.show(mExpandedBubble.getExpandedView(), mTempRect);
+ }
- updateUserEducationForLayoutDirection();
- addView(mUserEducationView);
+ /**
+ * Whether education view should show for the collapsed stack.
+ */
+ private boolean shouldShowStackEdu() {
+ final boolean seen = Prefs.getBoolean(getContext(),
+ Prefs.Key.HAS_SEEN_BUBBLES_EDUCATION, false /* default */);
+ final boolean shouldShow = !seen || BubbleDebugConfig.forceShowUserEducation(mContext);
+ if (BubbleDebugConfig.DEBUG_USER_EDUCATION) {
+ Log.d(TAG, "Show stack edu: " + shouldShow);
}
+ return shouldShow;
+ }
- if (mManageEducationView != null) {
- removeView(mManageEducationView);
+ /**
+ * @return true if education view for collapsed stack should show and was not showing before.
+ */
+ private boolean maybeShowStackEdu() {
+ if (!shouldShowStackEdu()) {
+ return false;
+ }
+ if (mStackEduView == null) {
+ mStackEduView = new StackEducationView(mContext);
+ addView(mStackEduView);
}
- mShouldShowManageEducation = shouldShowManageEducation();
- if (DEBUG_USER_EDUCATION) {
- Log.d(TAG, "shouldShowManageEducation: " + mShouldShowManageEducation);
+ return mStackEduView.show(mStackAnimationController.getStartPosition());
+ }
+
+ private void updateUserEdu() {
+ maybeShowStackEdu();
+ if (mManageEduView != null) {
+ mManageEduView.invalidate();
}
- if (mShouldShowManageEducation) {
- mManageEducationView = (ManageEducationView)
- mInflater.inflate(R.layout.bubbles_manage_button_education, this /* root */,
- false /* attachToRoot */);
- addView(mManageEducationView);
+ maybeShowManageEdu();
+ if (mStackEduView != null) {
+ mStackEduView.invalidate();
}
}
@@ -1164,9 +1167,9 @@ public class BubbleStackView extends FrameLayout
*/
public void onThemeChanged() {
setUpFlyout();
- setUpUserEducation();
setUpManageMenu();
updateOverflow();
+ updateUserEdu();
updateExpandedViewTheme();
}
@@ -1197,12 +1200,11 @@ public class BubbleStackView extends FrameLayout
public void onLayoutDirectionChanged(int direction) {
mManageMenu.setLayoutDirection(direction);
mFlyout.setLayoutDirection(direction);
- if (mUserEducationView != null) {
- mUserEducationView.setLayoutDirection(direction);
- updateUserEducationForLayoutDirection();
+ if (mStackEduView != null) {
+ mStackEduView.setLayoutDirection(direction);
}
- if (mManageEducationView != null) {
- mManageEducationView.setLayoutDirection(direction);
+ if (mManageEduView != null) {
+ mManageEduView.setLayoutDirection(direction);
}
updateExpandedViewDirection(direction);
}
@@ -1446,7 +1448,7 @@ public class BubbleStackView extends FrameLayout
Log.d(TAG, "addBubble: " + bubble);
}
- if (getBubbleCount() == 0 && mShouldShowUserEducation) {
+ if (getBubbleCount() == 0 && shouldShowStackEdu()) {
// Override the default stack position if we're showing user education.
mStackAnimationController.setStackPosition(
mStackAnimationController.getStartPosition());
@@ -1649,115 +1651,6 @@ public class BubbleStackView extends FrameLayout
notifyExpansionChanged(mExpandedBubble, mIsExpanded);
}
- /**
- * If necessary, shows the user education view for the bubble stack. This appears the first
- * time a user taps on a bubble.
- *
- * @return true if user education was shown, false otherwise.
- */
- private boolean maybeShowStackUserEducation() {
- if (mShouldShowUserEducation && mUserEducationView.getVisibility() != VISIBLE) {
- mUserEducationView.setAlpha(0);
- mUserEducationView.setVisibility(VISIBLE);
- updateUserEducationForLayoutDirection();
-
- // Post so we have height of mUserEducationView
- mUserEducationView.post(() -> {
- final int viewHeight = mUserEducationView.getHeight();
- PointF stackPosition = mStackAnimationController.getStartPosition();
- final float translationY = stackPosition.y + (mBubbleSize / 2) - (viewHeight / 2);
- mUserEducationView.setTranslationY(translationY);
- mUserEducationView.animate()
- .setDuration(ANIMATE_STACK_USER_EDUCATION_DURATION)
- .setInterpolator(FAST_OUT_SLOW_IN)
- .alpha(1);
- });
- Prefs.putBoolean(getContext(), HAS_SEEN_BUBBLES_EDUCATION, true);
- return true;
- }
- return false;
- }
-
- private void updateUserEducationForLayoutDirection() {
- if (mUserEducationView == null) {
- return;
- }
- LinearLayout textLayout = mUserEducationView.findViewById(R.id.user_education_view);
- TextView title = mUserEducationView.findViewById(R.id.user_education_title);
- TextView description = mUserEducationView.findViewById(R.id.user_education_description);
- boolean isLtr =
- getResources().getConfiguration().getLayoutDirection() == LAYOUT_DIRECTION_LTR;
- if (isLtr) {
- mUserEducationView.setLayoutDirection(LAYOUT_DIRECTION_LTR);
- textLayout.setBackgroundResource(R.drawable.bubble_stack_user_education_bg);
- title.setGravity(Gravity.LEFT);
- description.setGravity(Gravity.LEFT);
- } else {
- mUserEducationView.setLayoutDirection(LAYOUT_DIRECTION_RTL);
- textLayout.setBackgroundResource(R.drawable.bubble_stack_user_education_bg_rtl);
- title.setGravity(Gravity.RIGHT);
- description.setGravity(Gravity.RIGHT);
- }
- }
-
- /**
- * If necessary, hides the user education view for the bubble stack.
- *
- * @param fromExpansion if true this indicates the hide is happening due to the bubble being
- * expanded, false if due to a touch outside of the bubble stack.
- */
- void hideStackUserEducation(boolean fromExpansion) {
- if (mShouldShowUserEducation
- && mUserEducationView.getVisibility() == VISIBLE
- && !mAnimatingEducationAway) {
- mAnimatingEducationAway = true;
- mUserEducationView.animate()
- .alpha(0)
- .setDuration(fromExpansion
- ? ANIMATE_STACK_USER_EDUCATION_DURATION_SHORT
- : ANIMATE_STACK_USER_EDUCATION_DURATION)
- .withEndAction(() -> {
- mAnimatingEducationAway = false;
- mShouldShowUserEducation = shouldShowBubblesEducation();
- mUserEducationView.setVisibility(GONE);
- });
- }
- }
-
- /**
- * If necessary, toggles the user education view for the manage button. This is shown when the
- * bubble stack is expanded for the first time.
- *
- * @param show whether the user education view should show or not.
- */
- void maybeShowManageEducation(boolean show) {
- if (mManageEducationView == null) {
- return;
- }
- if (show
- && mShouldShowManageEducation
- && mManageEducationView.getVisibility() != VISIBLE
- && mIsExpanded
- && mExpandedBubble.getExpandedView() != null) {
- mManageEducationView.show(mExpandedBubble.getExpandedView(), mTempRect,
- () -> maybeShowManageEducation(false) /* run on click */);
- Prefs.putBoolean(getContext(), HAS_SEEN_BUBBLES_MANAGE_EDUCATION, true);
- } else if (!show
- && mManageEducationView.getVisibility() == VISIBLE
- && !mAnimatingManageEducationAway) {
- mManageEducationView.animate()
- .alpha(0)
- .setDuration(mIsExpansionAnimating
- ? ANIMATE_STACK_USER_EDUCATION_DURATION_SHORT
- : ANIMATE_STACK_USER_EDUCATION_DURATION)
- .withEndAction(() -> {
- mAnimatingManageEducationAway = false;
- mShouldShowManageEducation = shouldShowManageEducation();
- mManageEducationView.setVisibility(GONE);
- });
- }
- }
-
void showExpandedViewContents(int displayId) {
if (mExpandedBubble != null
&& mExpandedBubble.getExpandedView() != null
@@ -1791,7 +1684,9 @@ public class BubbleStackView extends FrameLayout
cancelDelayedExpandCollapseSwitchAnimations();
mIsExpanded = true;
- hideStackUserEducation(true /* fromExpansion */);
+ if (mStackEduView != null) {
+ mStackEduView.hide(true /* fromExpansion */);
+ }
beforeExpandedViewAnimation();
mBubbleContainer.setActiveController(mExpandedAnimationController);
@@ -1799,7 +1694,9 @@ public class BubbleStackView extends FrameLayout
updatePointerPosition();
mExpandedAnimationController.expandFromStack(() -> {
afterExpandedViewAnimation();
- maybeShowManageEducation(true);
+ if (mIsExpanded && mExpandedBubble.getExpandedView() != null) {
+ maybeShowManageEdu();
+ }
} /* after */);
mExpandedViewContainer.setTranslationX(0);
@@ -1936,7 +1833,9 @@ public class BubbleStackView extends FrameLayout
.withEndActions(() -> {
final BubbleViewProvider previouslySelected = mExpandedBubble;
beforeExpandedViewAnimation();
- maybeShowManageEducation(false);
+ if (mManageEduView != null) {
+ mManageEduView.hide(false /* fromExpansion */);
+ }
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "animateCollapse");
@@ -2104,8 +2003,8 @@ public class BubbleStackView extends FrameLayout
// from any location.
if (!mIsExpanded
|| mShowingManage
- || (mManageEducationView != null
- && mManageEducationView.getVisibility() == VISIBLE)) {
+ || (mManageEduView != null
+ && mManageEduView.getVisibility() == VISIBLE)) {
touchableRegion.setEmpty();
}
}
@@ -2289,7 +2188,7 @@ public class BubbleStackView extends FrameLayout
if (flyoutMessage == null
|| flyoutMessage.message == null
|| !bubble.showFlyout()
- || (mUserEducationView != null && mUserEducationView.getVisibility() == VISIBLE)
+ || (mStackEduView != null && mStackEduView.getVisibility() == VISIBLE)
|| isExpanded()
|| mIsExpansionAnimating
|| mIsGestureInProgress
@@ -2398,7 +2297,7 @@ public class BubbleStackView extends FrameLayout
* them.
*/
public void getTouchableRegion(Rect outRect) {
- if (mUserEducationView != null && mUserEducationView.getVisibility() == VISIBLE) {
+ if (mStackEduView != null && mStackEduView.getVisibility() == VISIBLE) {
// When user education shows then capture all touches
outRect.set(0, 0, getWidth(), getHeight());
return;
@@ -2770,18 +2669,6 @@ public class BubbleStackView extends FrameLayout
return mExpandedBubble.getExpandedView().performBackPressIfNeeded();
}
- /** Whether the educational view should appear for bubbles. **/
- private boolean shouldShowBubblesEducation() {
- return BubbleDebugConfig.forceShowUserEducation(getContext())
- || !Prefs.getBoolean(getContext(), HAS_SEEN_BUBBLES_EDUCATION, false);
- }
-
- /** Whether the educational view should appear for the expanded view "manage" button. **/
- private boolean shouldShowManageEducation() {
- return BubbleDebugConfig.forceShowUserEducation(getContext())
- || !Prefs.getBoolean(getContext(), HAS_SEEN_BUBBLES_MANAGE_EDUCATION, false);
- }
-
/** For debugging only */
List<Bubble> getBubblesOnScreen() {
List<Bubble> bubbles = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt b/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt
index c58ab31c4561..26a9773f9bb8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt
@@ -18,52 +18,56 @@ package com.android.systemui.bubbles
import android.content.Context
import android.graphics.Color
import android.graphics.Rect
-import android.util.AttributeSet
-import android.view.Gravity
+import android.view.LayoutInflater
import android.view.View
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import com.android.internal.util.ContrastColorUtil
import com.android.systemui.Interpolators
+import com.android.systemui.Prefs
+import com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION
import com.android.systemui.R
/**
- * Educational view to highlight the manage button that allows a user to configure the settings
+ * User education view to highlight the manage button that allows a user to configure the settings
* for the bubble. Shown only the first time a user expands a bubble.
*/
-class ManageEducationView @JvmOverloads constructor(
- context: Context?,
- attrs: AttributeSet? = null,
- defStyleAttr: Int = 0,
- defStyleRes: Int = 0
-) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {
+class ManageEducationView constructor(context: Context) : LinearLayout(context) {
+
+ private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleManageEducationView"
+ else BubbleDebugConfig.TAG_BUBBLES
+
+ private val ANIMATE_DURATION : Long = 200
+ private val ANIMATE_DURATION_SHORT : Long = 40
private val manageView by lazy { findViewById<View>(R.id.manage_education_view) }
private val manageButton by lazy { findViewById<Button>(R.id.manage) }
private val gotItButton by lazy { findViewById<Button>(R.id.got_it) }
private val titleTextView by lazy { findViewById<TextView>(R.id.user_education_title) }
private val descTextView by lazy { findViewById<TextView>(R.id.user_education_description) }
- private var isInflated = false
+
+ private var isHiding = false
init {
- this.visibility = View.GONE
- this.elevation = resources.getDimensionPixelSize(R.dimen.bubble_elevation).toFloat()
- this.layoutDirection = View.LAYOUT_DIRECTION_LOCALE
+ LayoutInflater.from(context).inflate(R.layout.bubbles_manage_button_education, this);
+ visibility = View.GONE
+ elevation = resources.getDimensionPixelSize(R.dimen.bubble_elevation).toFloat()
+
+ // BubbleStackView forces LTR by default
+ // since most of Bubble UI direction depends on positioning by the user.
+ // This view actually lays out differently in RTL, so we set layout LOCALE here.
+ layoutDirection = View.LAYOUT_DIRECTION_LOCALE
}
- override fun setLayoutDirection(direction: Int) {
- super.setLayoutDirection(direction)
- // setLayoutDirection runs before onFinishInflate
- // so skip if views haven't inflated; otherwise we'll get NPEs
- if (!isInflated) return
- setDirection()
+ override fun setLayoutDirection(layoutDirection: Int) {
+ super.setLayoutDirection(layoutDirection)
+ setDrawableDirection()
}
override fun onFinishInflate() {
super.onFinishInflate()
- isInflated = true
- setDirection()
+ layoutDirection = resources.configuration.layoutDirection
setTextColor()
}
@@ -78,29 +82,35 @@ class ManageEducationView @JvmOverloads constructor(
descTextView.setTextColor(textColor)
}
- fun setDirection() {
+ private fun setDrawableDirection() {
manageView.setBackgroundResource(
if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL)
R.drawable.bubble_stack_user_education_bg_rtl
else R.drawable.bubble_stack_user_education_bg)
- titleTextView.gravity = Gravity.START
- descTextView.gravity = Gravity.START
}
- fun show(expandedView: BubbleExpandedView, rect : Rect, hideMenu: Runnable) {
+ /**
+ * If necessary, toggles the user education view for the manage button. This is shown when the
+ * bubble stack is expanded for the first time.
+ *
+ * @param show whether the user education view should show or not.
+ */
+ fun show(expandedView: BubbleExpandedView, rect : Rect) {
+ if (visibility == VISIBLE) return
+
alpha = 0f
visibility = View.VISIBLE
post {
expandedView.getManageButtonBoundsOnScreen(rect)
- with(hideMenu) {
- manageButton
- .setOnClickListener {
- expandedView.findViewById<View>(R.id.settings_button).performClick()
- this.run()
- }
- gotItButton.setOnClickListener { this.run() }
- setOnClickListener { this.run() }
- }
+
+ manageButton
+ .setOnClickListener {
+ expandedView.findViewById<View>(R.id.settings_button).performClick()
+ hide(true /* isStackExpanding */)
+ }
+ gotItButton.setOnClickListener { hide(true /* isStackExpanding */) }
+ setOnClickListener { hide(true /* isStackExpanding */) }
+
with(manageView) {
translationX = 0f
val inset = resources.getDimensionPixelSize(
@@ -109,9 +119,27 @@ class ManageEducationView @JvmOverloads constructor(
}
bringToFront()
animate()
- .setDuration(BubbleStackView.ANIMATE_STACK_USER_EDUCATION_DURATION.toLong())
+ .setDuration(ANIMATE_DURATION)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.alpha(1f)
}
+ setShouldShow(false)
+ }
+
+ fun hide(isStackExpanding: Boolean) {
+ if (visibility != VISIBLE || isHiding) return
+
+ animate()
+ .withStartAction { isHiding = true }
+ .alpha(0f)
+ .setDuration(if (isStackExpanding) ANIMATE_DURATION_SHORT else ANIMATE_DURATION)
+ .withEndAction {
+ isHiding = false
+ visibility = GONE
+ };
+ }
+
+ private fun setShouldShow(shouldShow: Boolean) {
+ Prefs.putBoolean(context, HAS_SEEN_BUBBLES_MANAGE_EDUCATION, !shouldShow)
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt b/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt
new file mode 100644
index 000000000000..3e4c729d8315
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt
@@ -0,0 +1,134 @@
+/*
+ * 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.bubbles
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.PointF
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.LinearLayout
+import android.widget.TextView
+import com.android.internal.util.ContrastColorUtil
+import com.android.systemui.Interpolators
+import com.android.systemui.Prefs
+import com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_EDUCATION
+import com.android.systemui.R
+
+/**
+ * User education view to highlight the collapsed stack of bubbles.
+ * Shown only the first time a user taps the stack.
+ */
+class StackEducationView constructor(context: Context) : LinearLayout(context){
+
+ private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleStackEducationView"
+ else BubbleDebugConfig.TAG_BUBBLES
+
+ private val ANIMATE_DURATION : Long = 200
+ private val ANIMATE_DURATION_SHORT : Long = 40
+
+ private val view by lazy { findViewById<View>(R.id.stack_education_layout) }
+ private val titleTextView by lazy { findViewById<TextView>(R.id.stack_education_title) }
+ private val descTextView by lazy { findViewById<TextView>(R.id.stack_education_description) }
+
+ private var isHiding = false
+
+ init {
+ LayoutInflater.from(context).inflate(R.layout.bubble_stack_user_education, this);
+
+ visibility = View.GONE
+ elevation = resources.getDimensionPixelSize(R.dimen.bubble_elevation).toFloat()
+
+ // BubbleStackView forces LTR by default
+ // since most of Bubble UI direction depends on positioning by the user.
+ // This view actually lays out differently in RTL, so we set layout LOCALE here.
+ layoutDirection = View.LAYOUT_DIRECTION_LOCALE
+ }
+
+ override fun setLayoutDirection(layoutDirection: Int) {
+ super.setLayoutDirection(layoutDirection)
+ setDrawableDirection()
+ }
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ layoutDirection = resources.configuration.layoutDirection
+ setTextColor()
+ }
+
+ private fun setTextColor() {
+ val ta = mContext.obtainStyledAttributes(intArrayOf(android.R.attr.colorAccent,
+ android.R.attr.textColorPrimaryInverse))
+ val bgColor = ta.getColor(0 /* index */, Color.BLACK)
+ var textColor = ta.getColor(1 /* index */, Color.WHITE)
+ ta.recycle()
+ textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, true)
+ titleTextView.setTextColor(textColor)
+ descTextView.setTextColor(textColor)
+ }
+
+ private fun setDrawableDirection() {
+ view.setBackgroundResource(
+ if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR)
+ R.drawable.bubble_stack_user_education_bg
+ else R.drawable.bubble_stack_user_education_bg_rtl)
+ }
+
+ /**
+ * If necessary, shows the user education view for the bubble stack. This appears the first
+ * time a user taps on a bubble.
+ *
+ * @return true if user education was shown, false otherwise.
+ */
+ fun show(stackPosition: PointF) : Boolean{
+ if (visibility == VISIBLE) return false
+
+ setAlpha(0f)
+ setVisibility(View.VISIBLE)
+ post {
+ with(view) {
+ val bubbleSize = context.resources.getDimensionPixelSize(
+ R.dimen.individual_bubble_size)
+ translationY = stackPosition.y + bubbleSize / 2 - getHeight() / 2
+ }
+ animate()
+ .setDuration(ANIMATE_DURATION)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .alpha(1f)
+ }
+ setShouldShow(false)
+ return true
+ }
+
+ /**
+ * If necessary, hides the stack education view.
+ *
+ * @param fromExpansion if true this indicates the hide is happening due to the bubble being
+ * expanded, false if due to a touch outside of the bubble stack.
+ */
+ fun hide(fromExpansion: Boolean) {
+ if (visibility != VISIBLE || isHiding) return
+
+ animate()
+ .alpha(0f)
+ .setDuration(if (fromExpansion) ANIMATE_DURATION_SHORT else ANIMATE_DURATION)
+ .withEndAction { visibility = GONE }
+ }
+
+ private fun setShouldShow(shouldShow: Boolean) {
+ Prefs.putBoolean(context, HAS_SEEN_BUBBLES_EDUCATION, !shouldShow)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
index 1bda841d4a63..d930c98cabe1 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
@@ -87,6 +87,10 @@ class ControlsFavoritePersistenceWrapper(
* @param list a list of favorite controls. The list will be stored in the same order.
*/
fun storeFavorites(structures: List<StructureInfo>) {
+ if (structures.isEmpty() && !file.exists()) {
+ // Do not create a new file to store nothing
+ return
+ }
executor.execute {
Log.d(TAG, "Saving data to file: $file")
val atomicFile = AtomicFile(file)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index c683a87d6282..31830b94e8e4 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -72,8 +72,13 @@ class ControlAdapter(
TYPE_CONTROL -> {
ControlHolder(
layoutInflater.inflate(R.layout.controls_base_item, parent, false).apply {
- layoutParams.apply {
+ (layoutParams as ViewGroup.MarginLayoutParams).apply {
width = ViewGroup.LayoutParams.MATCH_PARENT
+ // Reset margins as they will be set through the decoration
+ topMargin = 0
+ bottomMargin = 0
+ leftMargin = 0
+ rightMargin = 0
}
elevation = this@ControlAdapter.elevation
background = parent.context.getDrawable(
@@ -386,7 +391,7 @@ class MarginItemDecorator(
val type = parent.adapter?.getItemViewType(position)
if (type == ControlAdapter.TYPE_CONTROL) {
outRect.apply {
- top = topMargin
+ top = topMargin * 2 // Use double margin, as we are not setting bottom
left = sideMargins
right = sideMargins
bottom = 0
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
index c95e81cd114b..596e440c3f4a 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
@@ -66,12 +66,6 @@ public abstract class DefaultServiceBinder {
@ClassKey(SystemUIAuxiliaryDumpService.class)
public abstract Service bindSystemUIAuxiliaryDumpService(SystemUIAuxiliaryDumpService service);
- /** */
- @Binds
- @IntoMap
- @ClassKey(TakeScreenshotService.class)
- public abstract Service bindTakeScreenshotService(TakeScreenshotService service);
-
/** Inject into RecordingService */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 5a7772320139..8a67e968ae13 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -61,7 +61,7 @@ import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.plugins.PluginManagerImpl;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -193,7 +193,7 @@ public class DependencyProvider {
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
CommandQueue commandQueue,
- Divider divider,
+ Optional<SplitScreen> splitScreenOptional,
Optional<Recents> recentsOptional,
Lazy<StatusBar> statusBarLazy,
ShadeController shadeController,
@@ -215,7 +215,7 @@ public class DependencyProvider {
sysUiFlagsContainer,
broadcastDispatcher,
commandQueue,
- divider,
+ splitScreenOptional,
recentsOptional,
statusBarLazy,
shadeController,
@@ -321,5 +321,4 @@ public class DependencyProvider {
public ModeSwitchesController providesModeSwitchesController(Context context) {
return new ModeSwitchesController(context);
}
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 7281faf1a2c4..b606201cc803 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -22,7 +22,6 @@ import com.android.systemui.InitController;
import com.android.systemui.SystemUIAppComponentFactory;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
-import com.android.systemui.onehanded.dagger.OneHandedModule;
import com.android.systemui.pip.phone.dagger.PipModule;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.InjectionInflationController;
@@ -37,7 +36,6 @@ import dagger.Subcomponent;
DefaultComponentBinder.class,
DependencyProvider.class,
DependencyBinder.class,
- OneHandedModule.class,
PipModule.class,
SystemServicesModule.class,
SystemUIBinder.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
index 7fe9faf5258c..ceb9aeee1d3b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
@@ -41,6 +41,7 @@ import android.hardware.SensorManager;
import android.hardware.SensorPrivacyManager;
import android.hardware.display.ColorDisplayManager;
import android.hardware.display.DisplayManager;
+import android.hardware.face.FaceManager;
import android.media.AudioManager;
import android.media.MediaRouter2Manager;
import android.media.session.MediaSessionManager;
@@ -59,6 +60,7 @@ import android.service.dreams.IDreamManager;
import android.telecom.TelecomManager;
import android.telephony.TelephonyManager;
import android.view.IWindowManager;
+import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
@@ -168,6 +170,14 @@ public class SystemServicesModule {
@Provides
@SysUISingleton
+ @Nullable
+ static FaceManager provideFaceManager(Context context) {
+ return context.getSystemService(FaceManager.class);
+
+ }
+
+ @Provides
+ @SysUISingleton
static IPackageManager provideIPackageManager() {
return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
}
@@ -312,6 +322,12 @@ public class SystemServicesModule {
@Provides
@SysUISingleton
+ static ViewConfiguration provideViewConfiguration(Context context) {
+ return ViewConfiguration.get(context);
+ }
+
+ @Provides
+ @SysUISingleton
static UserManager provideUserManager(Context context) {
return context.getSystemService(UserManager.class);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 0aebb7eaf823..9dfd9f8fd9bf 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -34,7 +34,6 @@ import com.android.systemui.power.PowerUI;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsModule;
import com.android.systemui.shortcut.ShortcutKeyDispatcher;
-import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.InstantAppNotifier;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -43,6 +42,7 @@ import com.android.systemui.theme.ThemeOverlayController;
import com.android.systemui.toast.ToastUI;
import com.android.systemui.util.leak.GarbageMonitor;
import com.android.systemui.volume.VolumeUI;
+import com.android.systemui.wmshell.WMShell;
import dagger.Binds;
import dagger.Module;
@@ -61,12 +61,6 @@ public abstract class SystemUIBinder {
@ClassKey(AuthController.class)
public abstract SystemUI bindAuthController(AuthController service);
- /** Inject into Divider. */
- @Binds
- @IntoMap
- @ClassKey(Divider.class)
- public abstract SystemUI bindDivider(Divider sysui);
-
/** Inject into GarbageMonitor.Service. */
@Binds
@IntoMap
@@ -187,4 +181,10 @@ public abstract class SystemUIBinder {
@IntoMap
@ClassKey(WindowMagnification.class)
public abstract SystemUI bindWindowMagnification(WindowMagnification sysui);
+
+ /** Inject into WMShell. */
+ @Binds
+ @IntoMap
+ @ClassKey(WMShell.class)
+ public abstract SystemUI bindWMShell(WMShell sysui);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index 3b225d5313c1..a021114c138b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -41,7 +41,6 @@ import com.android.systemui.qs.dagger.QSModule;
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImplementation;
-import com.android.systemui.stackdivider.DividerModule;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
@@ -75,7 +74,6 @@ import dagger.Provides;
* overridden by the System UI implementation.
*/
@Module(includes = {
- DividerModule.class,
QSModule.class,
WMShellModule.class
})
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index abfc2ab1c6e8..e985e3d7ef90 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -16,24 +16,17 @@
package com.android.systemui.dagger;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.pm.PackageManager;
-
-import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.assist.AssistModule;
import com.android.systemui.demomode.dagger.DemoModeModule;
import com.android.systemui.doze.dagger.DozeComponent;
-import com.android.systemui.dump.DumpManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.model.SysUiState;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.Recents;
+import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.settings.dagger.SettingsModule;
-import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
@@ -41,12 +34,10 @@ import com.android.systemui.statusbar.notification.people.PeopleHubModule;
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
-import com.android.systemui.statusbar.phone.KeyguardLiftController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.concurrency.ConcurrencyModule;
-import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.sensors.SensorModule;
import com.android.systemui.util.settings.SettingsUtilModule;
import com.android.systemui.util.time.SystemClock;
@@ -67,6 +58,7 @@ import dagger.Provides;
DemoModeModule.class,
LogModule.class,
PeopleHubModule.class,
+ ScreenshotModule.class,
SensorModule.class,
SettingsModule.class,
SettingsUtilModule.class
@@ -87,22 +79,6 @@ public abstract class SystemUIModule {
public abstract ContextComponentHelper bindComponentHelper(
ContextComponentResolver componentHelper);
- @SysUISingleton
- @Provides
- @Nullable
- static KeyguardLiftController provideKeyguardLiftController(
- Context context,
- StatusBarStateController statusBarStateController,
- AsyncSensorManager asyncSensorManager,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- DumpManager dumpManager) {
- if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
- return null;
- }
- return new KeyguardLiftController(statusBarStateController, asyncSensorManager,
- keyguardUpdateMonitor, dumpManager);
- }
-
/** */
@Binds
public abstract NotificationRowBinder bindNotificationRowBinder(
@@ -118,9 +94,6 @@ public abstract class SystemUIModule {
abstract CommandQueue optionalCommandQueue();
@BindsOptionalOf
- abstract Divider optionalDivider();
-
- @BindsOptionalOf
abstract HeadsUpManager optionalHeadsUpManager();
@BindsOptionalOf
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 1a1cc072c6bf..19b0ea1db04e 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -33,9 +33,6 @@ import java.io.PrintWriter;
import javax.inject.Inject;
-import dagger.Reusable;
-
-@Reusable // Don't create multiple DozeServices.
public class DozeService extends DreamService
implements DozeMachine.Service, RequestDoze, PluginListener<DozeServicePlugin> {
private static final String TAG = "DozeService";
@@ -60,7 +57,7 @@ public class DozeService extends DreamService
setWindowless(true);
mPluginManager.addPluginListener(this, DozeServicePlugin.class, false /* allowMultiple */);
- DozeComponent dozeComponent = mDozeComponentBuilder.build();
+ DozeComponent dozeComponent = mDozeComponentBuilder.build(this);
mDozeMachine = dozeComponent.getDozeMachine();
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java
index 247285434df9..05050f905e60 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java
@@ -19,6 +19,7 @@ package com.android.systemui.doze.dagger;
import com.android.systemui.doze.DozeMachine;
import com.android.systemui.doze.DozeService;
+import dagger.BindsInstance;
import dagger.Subcomponent;
/**
@@ -30,7 +31,7 @@ public interface DozeComponent {
/** Simple Builder for {@link DozeComponent}. */
@Subcomponent.Factory
interface Builder {
- DozeComponent build();
+ DozeComponent build(@BindsInstance DozeMachine.Service dozeMachineService);
}
/** Supply a {@link DozeMachine}. */
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
index a12e280fcca6..04f7c368fdc4 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
@@ -33,7 +33,6 @@ import com.android.systemui.doze.DozeScreenBrightness;
import com.android.systemui.doze.DozeScreenState;
import com.android.systemui.doze.DozeScreenStatePreventingAdapter;
import com.android.systemui.doze.DozeSensors;
-import com.android.systemui.doze.DozeService;
import com.android.systemui.doze.DozeSuspendScreenStatePreventingAdapter;
import com.android.systemui.doze.DozeTriggers;
import com.android.systemui.doze.DozeUi;
@@ -52,9 +51,9 @@ public abstract class DozeModule {
@Provides
@DozeScope
@WrappedService
- static DozeMachine.Service providesWrappedService(DozeService dozeService, DozeHost dozeHost,
- DozeParameters dozeParameters) {
- DozeMachine.Service wrappedService = dozeService;
+ static DozeMachine.Service providesWrappedService(DozeMachine.Service dozeMachineService,
+ DozeHost dozeHost, DozeParameters dozeParameters) {
+ DozeMachine.Service wrappedService = dozeMachineService;
wrappedService = new DozeBrightnessHostForwarder(wrappedService, dozeHost);
wrappedService = DozeScreenStatePreventingAdapter.wrapIfNeeded(
wrappedService, dozeParameters);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt
new file mode 100644
index 000000000000..9dcc3bb6fbdc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt
@@ -0,0 +1,193 @@
+/*
+ * 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.keyguard
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.content.res.Resources
+import android.database.ContentObserver
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.hardware.biometrics.BiometricSourceType
+import android.os.Handler
+import android.provider.Settings.System.SCREEN_BRIGHTNESS_FLOAT
+import android.util.MathUtils
+import android.view.View
+import android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
+import android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+import com.android.internal.annotations.VisibleForTesting
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.Dumpable
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.util.settings.GlobalSettings
+import com.android.systemui.util.settings.SystemSettings
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import java.lang.Float.max
+import java.util.concurrent.TimeUnit
+
+val DEFAULT_ANIMATION_DURATION = TimeUnit.SECONDS.toMillis(4)
+val MAX_SCREEN_BRIGHTNESS = 100 // 0..100
+val MAX_SCRIM_OPACTY = 50 // 0..100
+val DEFAULT_USE_FACE_WALLPAPER = false
+
+/**
+ * This class is responsible for ramping up the display brightness (and white overlay) in order
+ * to mitigate low light conditions when running face auth without an IR camera.
+ */
+@SysUISingleton
+open class FaceAuthScreenBrightnessController(
+ private val notificationShadeWindowController: NotificationShadeWindowController,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val resources: Resources,
+ private val globalSettings: GlobalSettings,
+ private val systemSettings: SystemSettings,
+ private val mainHandler: Handler,
+ private val dumpManager: DumpManager
+) : Dumpable {
+
+ private var userDefinedBrightness: Float = 1f
+ @VisibleForTesting
+ var useFaceAuthWallpaper = globalSettings
+ .getInt("sysui.use_face_auth_wallpaper", if (DEFAULT_USE_FACE_WALLPAPER) 1 else 0) == 1
+ private val brightnessAnimationDuration = globalSettings
+ .getLong("sysui.face_brightness_anim_duration", DEFAULT_ANIMATION_DURATION)
+ private val maxScreenBrightness = globalSettings
+ .getInt("sysui.face_max_brightness", MAX_SCREEN_BRIGHTNESS) / 100f
+ private val maxScrimOpacity = globalSettings
+ .getInt("sysui.face_max_scrim_opacity", MAX_SCRIM_OPACTY) / 100f
+ private val keyguardUpdateCallback = object : KeyguardUpdateMonitorCallback() {
+ override fun onBiometricRunningStateChanged(
+ running: Boolean,
+ biometricSourceType: BiometricSourceType?
+ ) {
+ if (biometricSourceType != BiometricSourceType.FACE) {
+ return
+ }
+ // TODO enable only when receiving a low-light error
+ overridingBrightness = running
+ }
+ }
+ private lateinit var whiteOverlay: View
+ private var brightnessAnimator: ValueAnimator? = null
+ private var overridingBrightness = false
+ set(value) {
+ if (field == value) {
+ return
+ }
+ field = value
+ brightnessAnimator?.cancel()
+
+ if (!value) {
+ notificationShadeWindowController.setFaceAuthDisplayBrightness(BRIGHTNESS_OVERRIDE_NONE)
+ if (whiteOverlay.alpha > 0) {
+ brightnessAnimator = createAnimator(whiteOverlay.alpha, 0f).apply {
+ duration = 200
+ addUpdateListener {
+ whiteOverlay.alpha = it.animatedValue as Float
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ whiteOverlay.visibility = View.INVISIBLE
+ brightnessAnimator = null
+ }
+ })
+ start()
+ }
+ }
+ return
+ }
+
+ val targetBrightness = max(maxScreenBrightness, userDefinedBrightness)
+ whiteOverlay.visibility = View.VISIBLE
+ brightnessAnimator = createAnimator(0f, 1f).apply {
+ duration = brightnessAnimationDuration
+ addUpdateListener {
+ val progress = it.animatedValue as Float
+ val brightnessProgress = MathUtils.constrainedMap(
+ userDefinedBrightness, targetBrightness, 0f, 0.5f, progress)
+ val scrimProgress = MathUtils.constrainedMap(
+ 0f, maxScrimOpacity, 0.5f, 1f, progress)
+ notificationShadeWindowController.setFaceAuthDisplayBrightness(brightnessProgress)
+ whiteOverlay.alpha = scrimProgress
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ brightnessAnimator = null
+ }
+ })
+ start()
+ }
+ }
+
+ @VisibleForTesting
+ open fun createAnimator(start: Float, end: Float) = ValueAnimator.ofFloat(start, end)
+
+ /**
+ * Returns a bitmap that should be used by the lock screen as a wallpaper, if face auth requires
+ * a secure wallpaper.
+ */
+ var faceAuthWallpaper: Bitmap? = null
+ get() {
+ val user = KeyguardUpdateMonitor.getCurrentUser()
+ if (useFaceAuthWallpaper && keyguardUpdateMonitor.isFaceAuthEnabledForUser(user)) {
+ val options = BitmapFactory.Options().apply {
+ inScaled = false
+ }
+ return BitmapFactory.decodeResource(resources, R.drawable.face_auth_wallpaper, options)
+ }
+ return null
+ }
+ private set
+
+ fun attach(overlayView: View) {
+ whiteOverlay = overlayView
+ whiteOverlay.focusable = FLAG_NOT_FOCUSABLE
+ whiteOverlay.background = ColorDrawable(Color.WHITE)
+ whiteOverlay.isEnabled = false
+ whiteOverlay.alpha = 0f
+ whiteOverlay.visibility = View.INVISIBLE
+
+ dumpManager.registerDumpable(this.javaClass.name, this)
+ keyguardUpdateMonitor.registerCallback(keyguardUpdateCallback)
+ systemSettings.registerContentObserver(SCREEN_BRIGHTNESS_FLOAT,
+ object : ContentObserver(mainHandler) {
+ override fun onChange(selfChange: Boolean) {
+ userDefinedBrightness = systemSettings.getFloat(SCREEN_BRIGHTNESS_FLOAT)
+ }
+ })
+ userDefinedBrightness = systemSettings.getFloat(SCREEN_BRIGHTNESS_FLOAT)
+ }
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+ pw.apply {
+ println("overridingBrightness: $overridingBrightness")
+ println("useFaceAuthWallpaper: $useFaceAuthWallpaper")
+ println("brightnessAnimator: $brightnessAnimator")
+ println("brightnessAnimationDuration: $brightnessAnimationDuration")
+ println("maxScreenBrightness: $maxScreenBrightness")
+ println("userDefinedBrightness: $userDefinedBrightness")
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 7c5dcd8960c4..c9164f0c4459 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -16,8 +16,13 @@
package com.android.systemui.keyguard.dagger;
+import android.annotation.Nullable;
import android.app.trust.TrustManager;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.hardware.face.FaceManager;
+import android.os.Handler;
import android.os.PowerManager;
import com.android.internal.widget.LockPatternUtils;
@@ -25,16 +30,25 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardViewController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.KeyguardLiftController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.InjectionInflationController;
+import com.android.systemui.util.sensors.AsyncSensorManager;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.settings.SystemSettings;
+import java.util.Optional;
import java.util.concurrent.Executor;
import dagger.Lazy;
@@ -82,4 +96,50 @@ public class KeyguardModule {
navigationModeController,
injectionInflationController);
}
+
+ @SysUISingleton
+ @Provides
+ @Nullable
+ static KeyguardLiftController provideKeyguardLiftController(
+ Context context,
+ StatusBarStateController statusBarStateController,
+ AsyncSensorManager asyncSensorManager,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ DumpManager dumpManager) {
+ if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ return null;
+ }
+ return new KeyguardLiftController(statusBarStateController, asyncSensorManager,
+ keyguardUpdateMonitor, dumpManager);
+ }
+
+ @SysUISingleton
+ @Provides
+ static Optional<FaceAuthScreenBrightnessController> provideFaceAuthScreenBrightnessController(
+ Context context,
+ NotificationShadeWindowController notificationShadeWindowController,
+ @Main Resources resources,
+ Handler handler,
+ @Nullable FaceManager faceManager,
+ PackageManager packageManager,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ GlobalSettings globalSetting,
+ SystemSettings systemSettings,
+ DumpManager dumpManager) {
+ if (faceManager == null || !packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ return Optional.empty();
+ }
+
+ // Cameras that support "self illumination," via IR for example, don't need low light
+ // environment mitigation.
+ boolean needsLowLightMitigation = faceManager.getSensorProperties().stream()
+ .anyMatch((properties) -> !properties.supportsSelfIllumination);
+ if (!needsLowLightMitigation) {
+ return Optional.empty();
+ }
+
+ return Optional.of(new FaceAuthScreenBrightnessController(
+ notificationShadeWindowController, keyguardUpdateMonitor, resources,
+ globalSetting, systemSettings, handler, dumpManager));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
index fdbff98ea831..6bd5274fa331 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
@@ -54,32 +54,35 @@ class MediaTimeoutListener @Inject constructor(
if (mediaListeners.containsKey(key)) {
return
}
- // Having an old key means that we're migrating from/to resumption. We should invalidate
- // the old listener and create a new one.
+ // Having an old key means that we're migrating from/to resumption. We should update
+ // the old listener to make sure that events will be dispatched to the new location.
val migrating = oldKey != null && key != oldKey
var wasPlaying = false
if (migrating) {
- if (mediaListeners.containsKey(oldKey)) {
- val oldListener = mediaListeners.remove(oldKey)
- wasPlaying = oldListener?.playing ?: false
- oldListener?.destroy()
+ val reusedListener = mediaListeners.remove(oldKey)
+ if (reusedListener != null) {
+ wasPlaying = reusedListener.playing ?: false
if (DEBUG) Log.d(TAG, "migrating key $oldKey to $key, for resumption")
+ reusedListener.mediaData = data
+ reusedListener.key = key
+ mediaListeners[key] = reusedListener
+ if (wasPlaying != reusedListener.playing) {
+ // If a player becomes active because of a migration, we'll need to broadcast
+ // its state. Doing it now would lead to reentrant callbacks, so let's wait
+ // until we're done.
+ mainExecutor.execute {
+ if (mediaListeners[key]?.playing == true) {
+ if (DEBUG) Log.d(TAG, "deliver delayed playback state for $key")
+ timeoutCallback.invoke(key, false /* timedOut */)
+ }
+ }
+ }
+ return
} else {
Log.w(TAG, "Old key $oldKey for player $key doesn't exist. Continuing...")
}
}
mediaListeners[key] = PlaybackStateListener(key, data)
-
- // If a player becomes active because of a migration, we'll need to broadcast its state.
- // Doing it now would lead to reentrant callbacks, so let's wait until we're done.
- if (migrating && mediaListeners[key]?.playing != wasPlaying) {
- mainExecutor.execute {
- if (mediaListeners[key]?.playing == true) {
- if (DEBUG) Log.d(TAG, "deliver delayed playback state for $key")
- timeoutCallback.invoke(key, false /* timedOut */)
- }
- }
- }
}
override fun onMediaDataRemoved(key: String) {
@@ -91,26 +94,34 @@ class MediaTimeoutListener @Inject constructor(
}
private inner class PlaybackStateListener(
- private val key: String,
+ var key: String,
data: MediaData
) : MediaController.Callback() {
var timedOut = false
var playing: Boolean? = null
+ var mediaData: MediaData = data
+ set(value) {
+ mediaController?.unregisterCallback(this)
+ field = value
+ mediaController = if (field.token != null) {
+ mediaControllerFactory.create(field.token)
+ } else {
+ null
+ }
+ mediaController?.registerCallback(this)
+ // Let's register the cancellations, but not dispatch events now.
+ // Timeouts didn't happen yet and reentrant events are troublesome.
+ processState(mediaController?.playbackState, dispatchEvents = false)
+ }
+
// Resume controls may have null token
- private val mediaController = if (data.token != null) {
- mediaControllerFactory.create(data.token)
- } else {
- null
- }
+ private var mediaController: MediaController? = null
private var cancellation: Runnable? = null
init {
- mediaController?.registerCallback(this)
- // Let's register the cancellations, but not dispatch events now.
- // Timeouts didn't happen yet and reentrant events are troublesome.
- processState(mediaController?.playbackState, dispatchEvents = false)
+ mediaData = data
}
fun destroy() {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 6c8a23ba96d1..aec3543de4eb 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -111,7 +111,6 @@ import com.android.systemui.assist.AssistHandleViewController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
import com.android.systemui.navigationbar.buttons.KeyButtonView;
@@ -123,7 +122,7 @@ import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
@@ -180,7 +179,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private final NavigationModeController mNavigationModeController;
private final BroadcastDispatcher mBroadcastDispatcher;
private final CommandQueue mCommandQueue;
- private final Divider mDivider;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private final Optional<Recents> mRecentsOptional;
private final SystemActions mSystemActions;
private final Handler mHandler;
@@ -377,22 +376,22 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
new DeviceConfig.OnPropertiesChangedListener() {
- @Override
- public void onPropertiesChanged(DeviceConfig.Properties properties) {
- if (properties.getKeyset().contains(NAV_BAR_HANDLE_FORCE_OPAQUE)) {
- mForceNavBarHandleOpaque = properties.getBoolean(
- NAV_BAR_HANDLE_FORCE_OPAQUE, /* defaultValue = */ true);
- }
- }
- };
+ @Override
+ public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ if (properties.getKeyset().contains(NAV_BAR_HANDLE_FORCE_OPAQUE)) {
+ mForceNavBarHandleOpaque = properties.getBoolean(
+ NAV_BAR_HANDLE_FORCE_OPAQUE, /* defaultValue = */ true);
+ }
+ }
+ };
private final DeviceProvisionedController.DeviceProvisionedListener mUserSetupListener =
new DeviceProvisionedController.DeviceProvisionedListener() {
- @Override
- public void onUserSetupChanged() {
- mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
- }
- };
+ @Override
+ public void onUserSetupChanged() {
+ mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
+ }
+ };
public NavigationBar(Context context,
WindowManager windowManager,
@@ -406,7 +405,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
StatusBarStateController statusBarStateController,
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
- CommandQueue commandQueue, Divider divider,
+ CommandQueue commandQueue,
+ Optional<SplitScreen> splitScreenOptional,
Optional<Recents> recentsOptional, Lazy<StatusBar> statusBarLazy,
ShadeController shadeController,
NotificationRemoteInputManager notificationRemoteInputManager,
@@ -430,7 +430,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mNavBarMode = navigationModeController.addListener(this);
mBroadcastDispatcher = broadcastDispatcher;
mCommandQueue = commandQueue;
- mDivider = divider;
+ mSplitScreenOptional = splitScreenOptional;
mRecentsOptional = recentsOptional;
mSystemActions = systemActions;
mHandler = mainHandler;
@@ -458,10 +458,10 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
lp.windowAnimations = 0;
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
- LayoutInflater layoutInflater = LayoutInflater.from(mContext);
- NavigationBarFrame frame = (NavigationBarFrame) layoutInflater.inflate(
+ NavigationBarFrame frame = (NavigationBarFrame) LayoutInflater.from(mContext).inflate(
R.layout.navigation_bar_window, null);
- View barView = layoutInflater.inflate(R.layout.navigation_bar, frame);
+ View barView = LayoutInflater.from(frame.getContext()).inflate(
+ R.layout.navigation_bar, frame);
barView.addOnAttachStateChangeListener(this);
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + barView);
@@ -528,6 +528,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
}
mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
+ mSplitScreenOptional.ifPresent(mNavigationBarView::registerDockedListener);
prepareNavigationBarView();
checkNavBarModes();
@@ -559,7 +560,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
setDisabled2Flags(mDisabledFlags2);
if (mIsOnDefaultDisplay) {
mAssistHandlerViewController =
- new AssistHandleViewController(mHandler, mNavigationBarView);
+ new AssistHandleViewController(mHandler, mNavigationBarView);
getBarTransitions().addDarkIntensityListener(mAssistHandlerViewController);
}
@@ -690,7 +691,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
return;
}
- if (mStartingQuickSwitchRotation == -1 || mDivider.isDividerVisible()) {
+ if (mStartingQuickSwitchRotation == -1 || mSplitScreenOptional
+ .map(SplitScreen::isDividerVisible).orElse(false)) {
// Hide the secondary home handle if we are in multiwindow since apps in multiwindow
// aren't allowed to set the display orientation
resetSecondaryHandle();
@@ -1121,7 +1123,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
}
mMetricsLogger.action(MetricsEvent.ACTION_ASSIST_LONG_PRESS);
mUiEventLogger.log(NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS);
- Bundle args = new Bundle();
+ Bundle args = new Bundle();
args.putInt(
AssistManager.INVOCATION_TYPE_KEY, AssistManager.INVOCATION_HOME_BUTTON_LONG_PRESS);
mAssistManagerLazy.get().startAssist(args);
@@ -1246,10 +1248,12 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private boolean onLongPressRecents() {
if (mRecentsOptional.isPresent() || !ActivityTaskManager.supportsMultiWindow(mContext)
- || !mDivider.getView().getSnapAlgorithm().isSplitScreenFeasible()
|| ActivityManager.isLowRamDeviceStatic()
// If we are connected to the overview service, then disable the recents button
- || mOverviewProxyService.getProxy() != null) {
+ || mOverviewProxyService.getProxy() != null
+ || !mSplitScreenOptional.map(splitScreen ->
+ splitScreen.getDividerView().getSnapAlgorithm().isSplitScreenFeasible())
+ .orElse(false)) {
return false;
}
@@ -1311,6 +1315,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
/**
* Returns the system UI flags corresponding the the current accessibility button state
+ *
* @param outFeedbackEnabled if non-null, sets it to true if accessibility feedback is enabled.
*/
public int getA11yButtonState(@Nullable boolean[] outFeedbackEnabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index fd157c632c7c..9b9dc6dec583 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -55,7 +55,7 @@ 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.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -96,7 +96,7 @@ public class NavigationBarController implements Callbacks,
private final SysUiState mSysUiFlagsContainer;
private final BroadcastDispatcher mBroadcastDispatcher;
private final CommandQueue mCommandQueue;
- private final Divider mDivider;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private final Optional<Recents> mRecentsOptional;
private final Lazy<StatusBar> mStatusBarLazy;
private final ShadeController mShadeController;
@@ -130,7 +130,7 @@ public class NavigationBarController implements Callbacks,
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
CommandQueue commandQueue,
- Divider divider,
+ Optional<SplitScreen> splitScreenOptional,
Optional<Recents> recentsOptional,
Lazy<StatusBar> statusBarLazy,
ShadeController shadeController,
@@ -152,7 +152,7 @@ public class NavigationBarController implements Callbacks,
mSysUiFlagsContainer = sysUiFlagsContainer;
mBroadcastDispatcher = broadcastDispatcher;
mCommandQueue = commandQueue;
- mDivider = divider;
+ mSplitScreenOptional = splitScreenOptional;
mRecentsOptional = recentsOptional;
mStatusBarLazy = statusBarLazy;
mShadeController = shadeController;
@@ -278,7 +278,7 @@ public class NavigationBarController implements Callbacks,
mSysUiFlagsContainer,
mBroadcastDispatcher,
mCommandQueue,
- mDivider,
+ mSplitScreenOptional,
mRecentsOptional,
mStatusBarLazy,
mShadeController,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index a3351838ecf2..8a468f6eb709 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -87,14 +87,13 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.LightBarTransitionsController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.StatusBar;
-import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -329,8 +328,8 @@ public class NavigationBarView extends FrameLayout implements
mContextualButtonGroup.addButton(accessibilityButton);
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
- mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
mFloatingRotationButton = new FloatingRotationButton(context);
+ mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
mRotationButtonController = new RotationButtonController(mLightContext,
mLightIconColor, mDarkIconColor,
isGesturalMode ? mFloatingRotationButton : rotateSuggestionButton,
@@ -912,9 +911,6 @@ public class NavigationBarView extends FrameLayout implements
mNavigationInflaterView.setButtonDispatchers(mButtonDispatchers);
getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
-
- Divider divider = Dependency.get(Divider.class);
- divider.registerInSplitScreenListener(mDockedListener);
updateOrientationViews();
reloadNavIcons();
}
@@ -1287,6 +1283,10 @@ public class NavigationBarView extends FrameLayout implements
return super.onApplyWindowInsets(insets);
}
+ void registerDockedListener(SplitScreen splitScreen) {
+ splitScreen.registerInSplitScreenListener(mDockedListener);
+ }
+
private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) {
pw.print(" " + caption + ": ");
if (button == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedController.java
index 90e7e12b2b47..bb59449d114d 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedController.java
@@ -49,7 +49,7 @@ import javax.inject.Inject;
* Manages and manipulates the one handed states, transitions, and gesture for phones.
*/
@SysUISingleton
-public class OneHandedManagerImpl implements OneHandedManager, Dumpable {
+public class OneHandedController implements Dumpable {
private static final String TAG = "OneHandedManager";
private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
"persist.debug.one_handed_offset_percentage";
@@ -106,7 +106,7 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable {
* Constructor of OneHandedManager
*/
@Inject
- public OneHandedManagerImpl(Context context,
+ public OneHandedController(Context context,
CommandQueue commandQueue,
DisplayController displayController,
NavigationModeController navigationModeController,
@@ -137,7 +137,7 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable {
*/
// TODO(b/161980408): Should remove extra constructor.
@VisibleForTesting
- OneHandedManagerImpl(Context context,
+ OneHandedController(Context context,
CommandQueue commandQueue,
DisplayController displayController,
OneHandedDisplayAreaOrganizer displayAreaOrganizer,
@@ -194,7 +194,6 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable {
/**
* Enters one handed mode.
*/
- @Override
public void startOneHanded() {
if (!mDisplayAreaOrganizer.isInOneHanded()) {
final int yOffSet = Math.round(getDisplaySize().y * mOffSetFraction);
@@ -206,7 +205,6 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable {
/**
* Exits one handed mode.
*/
- @Override
public void stopOneHanded() {
if (mDisplayAreaOrganizer.isInOneHanded()) {
mDisplayAreaOrganizer.scheduleOffset(0, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java
index 1420811b9b30..f3be699ab821 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java
@@ -103,7 +103,7 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback,
}
/**
- * Notified by {@link OneHandedManager}, when user update settings of Enabled or Disabled
+ * Notified by {@link OneHandedController}, when user update settings of Enabled or Disabled
*
* @param isEnabled is one handed settings enabled or not
*/
@@ -264,7 +264,7 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback,
}
/**
- * The touch(gesture) events to notify {@link OneHandedManager} start or stop one handed
+ * The touch(gesture) events to notify {@link OneHandedController} start or stop one handed
*/
public interface OneHandedGestureEventCallback {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java
index 0a7eb1bdada0..8265da6a5f14 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java
@@ -63,7 +63,7 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback, Dumpa
}
/**
- * Notified by {@link OneHandedManagerImpl}, when user update settings of Enabled or Disabled
+ * Notified by {@link OneHandedController}, when user update settings of Enabled or Disabled
*
* @param isEnabled is one handed settings enabled or not
*/
@@ -166,7 +166,7 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback, Dumpa
}
/**
- * The touch(gesture) events to notify {@link OneHandedManager} start or stop one handed
+ * The touch(gesture) events to notify {@link OneHandedController} start or stop one handed
*/
public interface OneHandedTouchEventCallback {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
index 8ef9b092bc00..0354c727c92c 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
@@ -158,9 +158,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Du
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
mDisplaySize.x, mTutorialAreaHeight, 0, 0,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT);
lp.gravity = Gravity.TOP | Gravity.LEFT;
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java
index cebcd4ceabe9..3348a06d5cac 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java
@@ -59,7 +59,7 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum
"com.android.internal.systemui.onehanded.gestural";
private static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
- private final OneHandedManagerImpl mOneHandedManager;
+ private final OneHandedController mOneHandedController;
private final CommandQueue mCommandQueue;
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
private final IOverlayManager mOverlayManager;
@@ -74,8 +74,8 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum
OneHandedEvents.writeEvent(enabled
? OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_ON
: OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_OFF);
- if (mOneHandedManager != null) {
- mOneHandedManager.setOneHandedEnabled(enabled);
+ if (mOneHandedController != null) {
+ mOneHandedController.setOneHandedEnabled(enabled);
}
// Also checks swipe to notification settings since they all need gesture overlay.
@@ -125,8 +125,8 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum
? OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_ON
: OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_OFF);
- if (mOneHandedManager != null) {
- mOneHandedManager.setTaskChangeToExit(enabled);
+ if (mOneHandedController != null) {
+ mOneHandedController.setTaskChangeToExit(enabled);
}
}
};
@@ -138,8 +138,8 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum
final boolean enabled =
OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
mContext.getContentResolver());
- if (mOneHandedManager != null) {
- mOneHandedManager.setSwipeToNotificationEnabled(enabled);
+ if (mOneHandedController != null) {
+ mOneHandedController.setSwipeToNotificationEnabled(enabled);
}
// Also checks one handed mode settings since they all need gesture overlay.
@@ -152,14 +152,14 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum
@Inject
public OneHandedUI(Context context,
CommandQueue commandQueue,
- OneHandedManagerImpl oneHandedManager,
+ OneHandedController oneHandedController,
ScreenLifecycle screenLifecycle) {
super(context);
if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) {
Log.i(TAG, "Device config SUPPORT_ONE_HANDED_MODE off");
mCommandQueue = null;
- mOneHandedManager = null;
+ mOneHandedController = null;
mOverlayManager = null;
mTimeoutHandler = null;
mScreenLifecycle = null;
@@ -167,7 +167,7 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum
}
mCommandQueue = commandQueue;
- mOneHandedManager = oneHandedManager;
+ mOneHandedController = oneHandedController;
mTimeoutHandler = OneHandedTimeoutHandler.get();
mScreenLifecycle = screenLifecycle;
mOverlayManager = IOverlayManager.Stub.asInterface(
@@ -260,13 +260,13 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum
}
private void updateSettings() {
- mOneHandedManager.setOneHandedEnabled(OneHandedSettingsUtil
+ mOneHandedController.setOneHandedEnabled(OneHandedSettingsUtil
.getSettingsOneHandedModeEnabled(mContext.getContentResolver()));
mTimeoutHandler.setTimeout(OneHandedSettingsUtil
.getSettingsOneHandedModeTimeout(mContext.getContentResolver()));
- mOneHandedManager.setTaskChangeToExit(OneHandedSettingsUtil
+ mOneHandedController.setTaskChangeToExit(OneHandedSettingsUtil
.getSettingsTapsAppToExit(mContext.getContentResolver()));
- mOneHandedManager.setSwipeToNotificationEnabled(OneHandedSettingsUtil
+ mOneHandedController.setSwipeToNotificationEnabled(OneHandedSettingsUtil
.getSettingsSwipeToNotificationEnabled(mContext.getContentResolver()));
}
@@ -295,7 +295,7 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum
* Trigger one handed more
*/
public void startOneHanded() {
- mOneHandedManager.startOneHanded();
+ mOneHandedController.startOneHanded();
OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_IN);
}
@@ -303,7 +303,7 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum
* Dismiss one handed more
*/
public void stopOneHanded() {
- mOneHandedManager.stopOneHanded();
+ mOneHandedController.stopOneHanded();
OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT);
}
@@ -314,8 +314,8 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum
final String innerPrefix = " ";
pw.println(TAG + "one handed states: ");
- if (mOneHandedManager != null) {
- ((OneHandedManagerImpl) mOneHandedManager).dump(fd, pw, args);
+ if (mOneHandedController != null) {
+ mOneHandedController.dump(fd, pw, args);
}
if (mTimeoutHandler != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index 4931388fe362..fd8ca8044acf 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -31,8 +31,6 @@ import com.android.systemui.Interpolators;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import javax.inject.Inject;
-
/**
* Controller class of PiP animations (both from and to PiP mode).
*/
@@ -88,7 +86,6 @@ public class PipAnimationController {
return handler;
});
- @Inject
PipAnimationController(PipSurfaceTransactionHelper helper) {
mSurfaceTransactionHelper = helper;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index d6aa61b0c767..b464e8adea59 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -40,13 +40,10 @@ import android.view.Gravity;
import android.window.WindowContainerTransaction;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import java.io.PrintWriter;
-import javax.inject.Inject;
-
/**
* Handles bounds calculation for PIP on Phone and other form factors, it keeps tracking variant
* state changes originated from Window Manager and is the source of truth for PiP window bounds.
@@ -57,10 +54,8 @@ public class PipBoundsHandler {
private static final String TAG = PipBoundsHandler.class.getSimpleName();
private static final float INVALID_SNAP_FRACTION = -1f;
- private final Context mContext;
private final PipSnapAlgorithm mSnapAlgorithm;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
- private final DisplayController mDisplayController;
private DisplayLayout mDisplayLayout;
private ComponentName mLastPipComponentName;
@@ -82,25 +77,10 @@ public class PipBoundsHandler {
private boolean mIsShelfShowing;
private int mShelfHeight;
- private final DisplayController.OnDisplaysChangedListener mDisplaysChangedListener =
- new DisplayController.OnDisplaysChangedListener() {
- @Override
- public void onDisplayAdded(int displayId) {
- if (displayId == mContext.getDisplayId()) {
- mDisplayLayout.set(mDisplayController.getDisplayLayout(displayId));
- }
- }
- };
-
- @Inject
- public PipBoundsHandler(Context context, PipSnapAlgorithm pipSnapAlgorithm,
- DisplayController displayController) {
- mContext = context;
- mSnapAlgorithm = pipSnapAlgorithm;
+ public PipBoundsHandler(Context context) {
+ mSnapAlgorithm = new PipSnapAlgorithm(context);
mDisplayLayout = new DisplayLayout();
- mDisplayController = displayController;
- mDisplayController.addDisplayWindowListener(mDisplaysChangedListener);
- reloadResources();
+ reloadResources(context);
// Initialize the aspect ratio to the default aspect ratio. Don't do this in reload
// resources as it would clobber mAspectRatio when entering PiP from fullscreen which
// triggers a configuration change and the resources to be reloaded.
@@ -110,8 +90,8 @@ public class PipBoundsHandler {
/**
* TODO: move the resources to SysUI package.
*/
- private void reloadResources() {
- final Resources res = mContext.getResources();
+ private void reloadResources(Context context) {
+ final Resources res = context.getResources();
mDefaultAspectRatio = res.getFloat(
com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
mDefaultStackGravity = res.getInteger(
@@ -133,6 +113,19 @@ public class PipBoundsHandler {
com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
}
+ /**
+ * Sets or update latest {@link DisplayLayout} when new display added or rotation callbacks
+ * from {@link DisplayController.OnDisplaysChangedListener}
+ * @param newDisplayLayout latest {@link DisplayLayout}
+ */
+ public void setDisplayLayout(DisplayLayout newDisplayLayout) {
+ mDisplayLayout.set(newDisplayLayout);
+ }
+
+ /**
+ * Update the Min edge size for {@link PipSnapAlgorithm} to calculate corresponding bounds
+ * @param minEdgeSize
+ */
public void setMinEdgeSize(int minEdgeSize) {
mCurrentMinSize = minEdgeSize;
}
@@ -217,6 +210,14 @@ public class PipBoundsHandler {
return mReentrySnapFraction != INVALID_SNAP_FRACTION;
}
+ /**
+ * The {@link PipSnapAlgorithm} is couple on display bounds
+ * @return {@link PipSnapAlgorithm}.
+ */
+ public PipSnapAlgorithm getSnapAlgorithm() {
+ return mSnapAlgorithm;
+ }
+
public Rect getDisplayBounds() {
return new Rect(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
}
@@ -237,8 +238,8 @@ public class PipBoundsHandler {
/**
* Responds to IPinnedStackListener on configuration change.
*/
- public void onConfigurationChanged() {
- reloadResources();
+ public void onConfigurationChanged(Context context) {
+ reloadResources(context);
}
/**
@@ -300,10 +301,10 @@ public class PipBoundsHandler {
* aren't in PIP because the rotation layout is used to calculate the proper insets for the
* next enter animation into PIP.
*/
- public void onDisplayRotationChangedNotInPip(int toRotation) {
+ public void onDisplayRotationChangedNotInPip(Context context, int toRotation) {
// Update the display layout, note that we have to do this on every rotation even if we
// aren't in PIP since we need to update the display layout to get the right resources
- mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
+ mDisplayLayout.rotateTo(context.getResources(), toRotation);
// Populate the new {@link #mDisplayInfo}.
// The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
@@ -319,7 +320,8 @@ public class PipBoundsHandler {
*
* @return {@code true} if internal {@link DisplayInfo} is rotated, {@code false} otherwise.
*/
- public boolean onDisplayRotationChanged(Rect outBounds, Rect oldBounds, Rect outInsetBounds,
+ public boolean onDisplayRotationChanged(Context context, Rect outBounds, Rect oldBounds,
+ Rect outInsetBounds,
int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) {
// Bail early if the event is not sent to current {@link #mDisplayInfo}
if ((displayId != mDisplayInfo.displayId) || (fromRotation == toRotation)) {
@@ -342,7 +344,7 @@ public class PipBoundsHandler {
final float snapFraction = getSnapFraction(postChangeStackBounds);
// Update the display layout
- mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
+ mDisplayLayout.rotateTo(context.getResources(), toRotation);
// Populate the new {@link #mDisplayInfo}.
// The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
@@ -546,5 +548,6 @@ public class PipBoundsHandler {
pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing);
pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight);
+ pw.println(innerPrefix + "mSnapAlgorithm" + mSnapAlgorithm);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
index a9b32d917d85..5d23e4207c33 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
@@ -22,24 +22,18 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.util.Size;
-import javax.inject.Inject;
-
/**
* Calculates the snap targets and the snap position for the PIP given a position and a velocity.
* All bounds are relative to the display top/left.
*/
public class PipSnapAlgorithm {
- private final Context mContext;
-
private final float mDefaultSizePercent;
private final float mMinAspectRatioForMinSize;
private final float mMaxAspectRatioForMinSize;
- @Inject
public PipSnapAlgorithm(Context context) {
Resources res = context.getResources();
- mContext = context;
mDefaultSizePercent = res.getFloat(
com.android.internal.R.dimen.config_pictureInPictureDefaultSizePercent);
mMaxAspectRatioForMinSize = res.getFloat(
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
index e88451ca00b5..3e98169c5b2b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
@@ -27,8 +27,6 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.wm.shell.R;
-import javax.inject.Inject;
-
/**
* Abstracts the common operations on {@link SurfaceControl.Transaction} for PiP transition.
*/
@@ -46,7 +44,6 @@ public class PipSurfaceTransactionHelper implements ConfigurationController.Conf
private final RectF mTmpDestinationRectF = new RectF();
private final Rect mTmpDestinationRect = new Rect();
- @Inject
public PipSurfaceTransactionHelper(Context context, ConfigurationController configController) {
final Resources res = context.getResources();
mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 0e60c83b8392..7421ec14398b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -58,8 +58,9 @@ import android.window.WindowOrganizer;
import com.android.internal.os.SomeArgs;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.pip.phone.PipUpdateThread;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import java.io.PrintWriter;
@@ -68,10 +69,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.function.Consumer;
-import javax.inject.Inject;
-
/**
* Manages PiP tasks such as resize and offset.
*
@@ -84,7 +84,7 @@ import javax.inject.Inject;
* see also {@link com.android.systemui.pip.phone.PipMotionHelper}.
*/
@SysUISingleton
-public class PipTaskOrganizer extends TaskOrganizer implements
+public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganizer.TaskListener,
DisplayController.OnDisplaysChangedListener {
private static final String TAG = PipTaskOrganizer.class.getSimpleName();
private static final boolean DEBUG = false;
@@ -105,7 +105,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements
private final int mEnterExitAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
private final Map<IBinder, Configuration> mInitialState = new HashMap<>();
- private final Divider mSplitDivider;
+ private final Optional<SplitScreen> mSplitScreenOptional;
+ protected final ShellTaskOrganizer mTaskOrganizer;
// These callbacks are called on the update thread
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
@@ -205,23 +206,24 @@ public class PipTaskOrganizer extends TaskOrganizer implements
*/
private boolean mShouldDeferEnteringPip;
- @Inject
public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
- @Nullable Divider divider,
+ Optional<SplitScreen> splitScreenOptional,
@NonNull DisplayController displayController,
- @NonNull PipAnimationController pipAnimationController,
- @NonNull PipUiEventLogger pipUiEventLogger) {
+ @NonNull PipUiEventLogger pipUiEventLogger,
+ @NonNull ShellTaskOrganizer shellTaskOrganizer) {
mMainHandler = new Handler(Looper.getMainLooper());
mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
mPipBoundsHandler = boundsHandler;
mEnterExitAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipResizeAnimationDuration);
mSurfaceTransactionHelper = surfaceTransactionHelper;
- mPipAnimationController = pipAnimationController;
+ mPipAnimationController = new PipAnimationController(mSurfaceTransactionHelper);
mPipUiEventLoggerLogger = pipUiEventLogger;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
- mSplitDivider = divider;
+ mSplitScreenOptional = splitScreenOptional;
+ mTaskOrganizer = shellTaskOrganizer;
+ mTaskOrganizer.addListener(this, WINDOWING_MODE_PINNED);
displayController.addDisplayWindowListener(this);
}
@@ -316,7 +318,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements
: WINDOWING_MODE_FULLSCREEN);
wct.setBounds(mToken, destinationBounds);
wct.setBoundsChangeTransaction(mToken, tx);
- applySyncTransaction(wct, new WindowContainerTransactionCallback() {
+ mTaskOrganizer.applySyncTransaction(wct, new WindowContainerTransactionCallback() {
@Override
public void onTransactionReady(int id, SurfaceControl.Transaction t) {
t.apply();
@@ -335,9 +337,11 @@ public class PipTaskOrganizer extends TaskOrganizer implements
wct.setWindowingMode(mToken, getOutPipWindowingMode());
// Simply reset the activity mode set prior to the animation running.
wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
- if (mSplitDivider != null && direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
- wct.reparent(mToken, mSplitDivider.getSecondaryRoot(), true /* onTop */);
- }
+ mSplitScreenOptional.ifPresent(splitScreen -> {
+ if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
+ wct.reparent(mToken, splitScreen.getSecondaryRoot(), true /* onTop */);
+ }
+ });
}
/**
@@ -446,7 +450,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements
wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
wct.setBounds(mToken, destinationBounds);
wct.scheduleFinishEnterPip(mToken, destinationBounds);
- applySyncTransaction(wct, new WindowContainerTransactionCallback() {
+ mTaskOrganizer.applySyncTransaction(wct, new WindowContainerTransactionCallback() {
@Override
public void onTransactionReady(int id, SurfaceControl.Transaction t) {
t.apply();
@@ -543,11 +547,6 @@ public class PipTaskOrganizer extends TaskOrganizer implements
}
@Override
- public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
- // Do nothing
- }
-
- @Override
public void onFixedRotationStarted(int displayId, int newRotation) {
mShouldDeferEnteringPip = true;
}
@@ -938,20 +937,26 @@ public class PipTaskOrganizer extends TaskOrganizer implements
}
/**
- * Sync with {@link #mSplitDivider} on destination bounds if PiP is going to split screen.
+ * Sync with {@link SplitScreen} on destination bounds if PiP is going to split screen.
*
* @param destinationBoundsOut contain the updated destination bounds if applicable
* @return {@code true} if destinationBounds is altered for split screen
*/
private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut) {
- if (mSplitDivider == null || !mSplitDivider.isDividerVisible()) {
- // bail early if system is not in split screen mode
+ if (!mSplitScreenOptional.isPresent()) {
return false;
}
+
+ SplitScreen splitScreen = mSplitScreenOptional.get();
+ if (!splitScreen.isDividerVisible()) {
+ // fail early if system is not in split screen mode
+ return false;
+ }
+
// PiP window will go to split-secondary mode instead of fullscreen, populates the
// split screen bounds here.
- destinationBoundsOut.set(
- mSplitDivider.getView().getNonMinimizedSplitScreenSecondaryBounds());
+ destinationBoundsOut.set(splitScreen.getDividerView()
+ .getNonMinimizedSplitScreenSecondaryBounds());
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java b/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java
index 7ce2028b5f1b..8bcaa8ab5404 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java
@@ -22,9 +22,6 @@ import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dagger.SysUISingleton;
-import javax.inject.Inject;
-
-
/**
* Helper class that ends PiP log to UiEvent, see also go/uievent
*/
@@ -35,7 +32,6 @@ public class PipUiEventLogger {
private TaskInfo mTaskInfo;
- @Inject
public PipUiEventLogger(UiEventLogger uiEventLogger) {
mUiEventLogger = uiEventLogger;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index facb3966f78c..d8864ec72dc3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -46,7 +46,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.model.SysUiState;
import com.android.systemui.pip.BasePipManager;
import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipSnapAlgorithm;
+import com.android.systemui.pip.PipSurfaceTransactionHelper;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
@@ -56,13 +56,16 @@ import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.FloatingContentCoordinator;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import java.io.PrintWriter;
+import java.util.Optional;
import javax.inject.Inject;
@@ -82,15 +85,17 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
private final Rect mTmpNormalBounds = new Rect();
protected final Rect mReentryBounds = new Rect();
- private PipBoundsHandler mPipBoundsHandler;
+ private DisplayController mDisplayController;
private InputConsumerController mInputConsumerController;
+ private PipAppOpsListener mAppOpsListener;
private PipMediaController mMediaController;
private PipTouchHandler mTouchHandler;
private PipTaskOrganizer mPipTaskOrganizer;
- private PipAppOpsListener mAppOpsListener;
+ private PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;
private IPinnedStackAnimationListener mPinnedStackAnimationRecentsListener;
private boolean mIsInFixedRotation;
+ protected PipBoundsHandler mPipBoundsHandler;
protected PipMenuActivityController mMenuController;
/**
@@ -101,15 +106,16 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
if (!mPipTaskOrganizer.isInPip() || mPipTaskOrganizer.isDeferringEnterPipAnimation()) {
// Skip if we aren't in PIP or haven't actually entered PIP yet. We still need to update
// the display layout in the bounds handler in this case.
- mPipBoundsHandler.onDisplayRotationChangedNotInPip(toRotation);
+ mPipBoundsHandler.onDisplayRotationChangedNotInPip(mContext, toRotation);
return;
}
// If there is an animation running (ie. from a shelf offset), then ensure that we calculate
// the bounds for the next orientation using the destination bounds of the animation
// TODO: Techincally this should account for movement animation bounds as well
Rect currentBounds = mPipTaskOrganizer.getCurrentOrAnimatingBounds();
- final boolean changed = mPipBoundsHandler.onDisplayRotationChanged(mTmpNormalBounds,
- currentBounds, mTmpInsetBounds, displayId, fromRotation, toRotation, t);
+ final boolean changed = mPipBoundsHandler.onDisplayRotationChanged(mContext,
+ mTmpNormalBounds, currentBounds, mTmpInsetBounds, displayId, fromRotation,
+ toRotation, t);
if (changed) {
// If the pip was in the offset zone earlier, adjust the new bounds to the bottom of the
// movement bounds
@@ -135,16 +141,22 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
private DisplayController.OnDisplaysChangedListener mFixedRotationListener =
new DisplayController.OnDisplaysChangedListener() {
- @Override
- public void onFixedRotationStarted(int displayId, int newRotation) {
- mIsInFixedRotation = true;
- }
-
- @Override
- public void onFixedRotationFinished(int displayId) {
- mIsInFixedRotation = false;
- }
- };
+ @Override
+ public void onFixedRotationStarted(int displayId, int newRotation) {
+ mIsInFixedRotation = true;
+ }
+
+ @Override
+ public void onFixedRotationFinished(int displayId) {
+ mIsInFixedRotation = false;
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ mPipBoundsHandler.setDisplayLayout(
+ mDisplayController.getDisplayLayout(displayId));
+ }
+ };
/**
* Handler for system task stack changes.
@@ -228,7 +240,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
@Override
public void onConfigurationChanged() {
- mHandler.post(() -> mPipBoundsHandler.onConfigurationChanged());
+ mHandler.post(() -> mPipBoundsHandler.onConfigurationChanged(mContext));
}
@Override
@@ -256,15 +268,14 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
@Inject
public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
@PipMenuActivityClass Class<?> pipMenuActivityClass,
+ ConfigurationController configController,
+ DeviceConfigProxy deviceConfig,
DisplayController displayController,
+ Optional<SplitScreen> splitScreenOptional,
FloatingContentCoordinator floatingContentCoordinator,
- DeviceConfigProxy deviceConfig,
- PipBoundsHandler pipBoundsHandler,
- PipSnapAlgorithm pipSnapAlgorithm,
- PipTaskOrganizer pipTaskOrganizer,
SysUiState sysUiState,
- ConfigurationController configController,
- PipUiEventLogger pipUiEventLogger) {
+ PipUiEventLogger pipUiEventLogger,
+ ShellTaskOrganizer shellTaskOrganizer) {
mContext = context;
mActivityManager = ActivityManager.getService();
@@ -276,8 +287,12 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
}
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
- mPipBoundsHandler = pipBoundsHandler;
- mPipTaskOrganizer = pipTaskOrganizer;
+ mDisplayController = displayController;
+ mPipBoundsHandler = new PipBoundsHandler(mContext);
+ mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context, configController);
+ mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler,
+ mPipSurfaceTransactionHelper, splitScreenOptional, mDisplayController,
+ pipUiEventLogger, shellTaskOrganizer);
mPipTaskOrganizer.registerPipTransitionCallback(this);
mInputConsumerController = InputConsumerController.getPipInputConsumer();
mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
@@ -285,8 +300,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
mMediaController, mInputConsumerController);
mTouchHandler = new PipTouchHandler(context, mActivityManager,
mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer,
- floatingContentCoordinator, deviceConfig, pipSnapAlgorithm, sysUiState,
- pipUiEventLogger);
+ floatingContentCoordinator, deviceConfig, sysUiState, pipUiEventLogger);
mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
mTouchHandler.getMotionHelper());
displayController.addDisplayChangingController(mRotationController);
@@ -301,7 +315,6 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
configController.addCallback(mOverlayChangedListener);
try {
- mPipTaskOrganizer.registerOrganizer(WINDOWING_MODE_PINNED);
ActivityManager.StackInfo stackInfo = ActivityTaskManager.getService().getStackInfo(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
if (stackInfo != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index ecd315b336f2..1b84c1417c51 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -58,7 +58,6 @@ import com.android.systemui.R;
import com.android.systemui.model.SysUiState;
import com.android.systemui.pip.PipAnimationController;
import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.shared.system.InputConsumerController;
@@ -99,7 +98,6 @@ public class PipTouchHandler {
private IPinnedStackController mPinnedStackController;
private final PipMenuActivityController mMenuController;
- private final PipSnapAlgorithm mSnapAlgorithm;
private final AccessibilityManager mAccessibilityManager;
private boolean mShowPipMenuOnAnimationEnd = false;
@@ -216,20 +214,19 @@ public class PipTouchHandler {
PipTaskOrganizer pipTaskOrganizer,
FloatingContentCoordinator floatingContentCoordinator,
DeviceConfigProxy deviceConfig,
- PipSnapAlgorithm pipSnapAlgorithm,
SysUiState sysUiState,
PipUiEventLogger pipUiEventLogger) {
// Initialize the Pip input consumer
mContext = context;
mActivityManager = activityManager;
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+ mPipBoundsHandler = pipBoundsHandler;
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mMenuController = menuController;
mMenuController.addListener(new PipMenuListener());
- mSnapAlgorithm = pipSnapAlgorithm;
mGesture = new DefaultPipTouchGesture();
mMotionHelper = new PipMotionHelper(mContext, pipTaskOrganizer, mMenuController,
- mSnapAlgorithm, floatingContentCoordinator);
+ mPipBoundsHandler.getSnapAlgorithm(), floatingContentCoordinator);
mPipResizeGestureHandler =
new PipResizeGestureHandler(context, pipBoundsHandler, mMotionHelper,
deviceConfig, pipTaskOrganizer, this::getMovementBounds,
@@ -248,11 +245,10 @@ public class PipTouchHandler {
inputConsumerController.setInputListener(this::handleTouchEvent);
inputConsumerController.setRegistrationListener(this::onRegistrationChanged);
- mPipBoundsHandler = pipBoundsHandler;
mFloatingContentCoordinator = floatingContentCoordinator;
mConnection = new PipAccessibilityInteractionConnection(mContext, mMotionHelper,
- pipTaskOrganizer, pipSnapAlgorithm, this::onAccessibilityShowMenu,
- this::updateMovementBounds, mHandler);
+ pipTaskOrganizer, mPipBoundsHandler.getSnapAlgorithm(),
+ this::onAccessibilityShowMenu, this::updateMovementBounds, mHandler);
mPipUiEventLogger = pipUiEventLogger;
@@ -419,7 +415,8 @@ public class PipTouchHandler {
public void adjustBoundsForRotation(Rect outBounds, Rect curBounds, Rect insetBounds) {
final Rect toMovementBounds = new Rect();
- mSnapAlgorithm.getMovementBounds(outBounds, insetBounds, toMovementBounds, 0);
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(outBounds, insetBounds,
+ toMovementBounds, 0);
final int prevBottom = mMovementBounds.bottom - mMovementBoundsExtraOffsets;
if ((prevBottom - mBottomOffsetBufferPx) <= curBounds.top) {
outBounds.offsetTo(outBounds.left, toMovementBounds.bottom);
@@ -450,26 +447,26 @@ public class PipTouchHandler {
// Re-calculate the expanded bounds
mNormalBounds.set(normalBounds);
Rect normalMovementBounds = new Rect();
- mSnapAlgorithm.getMovementBounds(mNormalBounds, insetBounds, normalMovementBounds,
- bottomOffset);
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(mNormalBounds, insetBounds,
+ normalMovementBounds, bottomOffset);
if (mMovementBounds.isEmpty()) {
// mMovementBounds is not initialized yet and a clean movement bounds without
// bottom offset shall be used later in this function.
- mSnapAlgorithm.getMovementBounds(curBounds, insetBounds, mMovementBounds,
- 0 /* bottomOffset */);
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(curBounds, insetBounds,
+ mMovementBounds, 0 /* bottomOffset */);
}
// Calculate the expanded size
float aspectRatio = (float) normalBounds.width() / normalBounds.height();
Point displaySize = new Point();
mContext.getDisplay().getRealSize(displaySize);
- Size expandedSize = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio,
+ Size expandedSize = mPipBoundsHandler.getSnapAlgorithm().getSizeForAspectRatio(aspectRatio,
mExpandedShortestEdgeSize, displaySize.x, displaySize.y);
mExpandedBounds.set(0, 0, expandedSize.getWidth(), expandedSize.getHeight());
Rect expandedMovementBounds = new Rect();
- mSnapAlgorithm.getMovementBounds(mExpandedBounds, insetBounds, expandedMovementBounds,
- bottomOffset);
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(mExpandedBounds, insetBounds,
+ expandedMovementBounds, bottomOffset);
mPipResizeGestureHandler.updateMinSize(mNormalBounds.width(), mNormalBounds.height());
mPipResizeGestureHandler.updateMaxSize(mExpandedBounds.width(), mExpandedBounds.height());
@@ -489,7 +486,7 @@ public class PipTouchHandler {
} else {
final boolean isExpanded = mMenuState == MENU_STATE_FULL && willResizeMenu();
final Rect toMovementBounds = new Rect();
- mSnapAlgorithm.getMovementBounds(curBounds, insetBounds,
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(curBounds, insetBounds,
toMovementBounds, mIsImeShowing ? mImeHeight : 0);
final int prevBottom = mMovementBounds.bottom - mMovementBoundsExtraOffsets;
// This is to handle landscape fullscreen IMEs, don't apply the extra offset in this
@@ -500,8 +497,8 @@ public class PipTouchHandler {
if (isExpanded) {
curBounds.set(mExpandedBounds);
- mSnapAlgorithm.applySnapFraction(curBounds, toMovementBounds,
- mSavedSnapFraction);
+ mPipBoundsHandler.getSnapAlgorithm().applySnapFraction(curBounds,
+ toMovementBounds, mSavedSnapFraction);
}
if (prevBottom < toBottom) {
@@ -608,7 +605,7 @@ public class PipTouchHandler {
.spring(DynamicAnimation.TRANSLATION_Y,
mTargetViewContainer.getHeight(),
mTargetSpringConfig)
- .withEndActions(() -> mTargetViewContainer.setVisibility(View.GONE))
+ .withEndActions(() -> mTargetViewContainer.setVisibility(View.GONE))
.start();
((TransitionDrawable) mTargetViewContainer.getBackground()).reverseTransition(
@@ -844,8 +841,8 @@ public class PipTouchHandler {
if (mDeferResizeToNormalBoundsUntilRotation == -1) {
Rect restoreBounds = new Rect(getUserResizeBounds());
Rect restoredMovementBounds = new Rect();
- mSnapAlgorithm.getMovementBounds(restoreBounds, mInsetBounds,
- restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(restoreBounds,
+ mInsetBounds, restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
mMotionHelper.animateToUnexpandedState(restoreBounds, mSavedSnapFraction,
restoredMovementBounds, mMovementBounds, false /* immediate */);
mSavedSnapFraction = -1f;
@@ -1025,25 +1022,25 @@ public class PipTouchHandler {
mMenuController.hideMenu();
}
}
- };
+ }
/**
* Updates the current movement bounds based on whether the menu is currently visible and
* resized.
*/
private void updateMovementBounds() {
- mSnapAlgorithm.getMovementBounds(mMotionHelper.getBounds(), mInsetBounds,
- mMovementBounds, mIsImeShowing ? mImeHeight : 0);
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(mMotionHelper.getBounds(),
+ mInsetBounds, mMovementBounds, mIsImeShowing ? mImeHeight : 0);
mMotionHelper.setCurrentMovementBounds(mMovementBounds);
boolean isMenuExpanded = mMenuState == MENU_STATE_FULL;
mPipBoundsHandler.setMinEdgeSize(
- isMenuExpanded && willResizeMenu() ? mExpandedShortestEdgeSize : 0);
+ isMenuExpanded && willResizeMenu() ? mExpandedShortestEdgeSize : 0);
}
private Rect getMovementBounds(Rect curBounds) {
Rect movementBounds = new Rect();
- mSnapAlgorithm.getMovementBounds(curBounds, mInsetBounds,
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(curBounds, mInsetBounds,
movementBounds, mIsImeShowing ? mImeHeight : 0);
return movementBounds;
}
@@ -1075,6 +1072,7 @@ public class PipTouchHandler {
pw.println(innerPrefix + "mSavedSnapFraction=" + mSavedSnapFraction);
pw.println(innerPrefix + "mEnableDragToEdgeDismiss=" + mEnableDismissDragToEdge);
pw.println(innerPrefix + "mMovementBoundsExtraOffsets=" + mMovementBoundsExtraOffsets);
+ mPipBoundsHandler.dump(pw, innerPrefix);
mTouchState.dump(pw, innerPrefix);
mMotionHelper.dump(pw, innerPrefix);
if (mPipResizeGestureHandler != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 74dc003bd8b6..8d0948b16d20 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -20,6 +20,7 @@ import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import android.annotation.NonNull;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityTaskManager;
@@ -54,14 +55,19 @@ import com.android.systemui.pip.BasePipManager;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipSurfaceTransactionHelper;
import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayController;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import javax.inject.Inject;
@@ -111,6 +117,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
private Context mContext;
private PipBoundsHandler mPipBoundsHandler;
private PipTaskOrganizer mPipTaskOrganizer;
+ private PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;
private IActivityTaskManager mActivityTaskManager;
private MediaSessionManager mMediaSessionManager;
private int mState = STATE_NO_PIP;
@@ -229,17 +236,18 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
@Inject
public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
- PipBoundsHandler pipBoundsHandler,
- PipTaskOrganizer pipTaskOrganizer,
- PipSurfaceTransactionHelper surfaceTransactionHelper,
- Divider divider) {
+ ConfigurationController configController,
+ DisplayController displayController,
+ Optional<SplitScreen> splitScreenOptional,
+ @NonNull PipUiEventLogger pipUiEventLogger,
+ ShellTaskOrganizer shellTaskOrganizer) {
if (mInitialized) {
return;
}
mInitialized = true;
mContext = context;
- mPipBoundsHandler = pipBoundsHandler;
+ mPipBoundsHandler = new PipBoundsHandler(mContext);
// Ensure that we have the display info in case we get calls to update the bounds before the
// listener calls back
final DisplayInfo displayInfo = new DisplayInfo();
@@ -248,7 +256,10 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
mResizeAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipResizeAnimationDuration);
- mPipTaskOrganizer = pipTaskOrganizer;
+ mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context, configController);
+ mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler,
+ mPipSurfaceTransactionHelper, splitScreenOptional, displayController,
+ pipUiEventLogger, shellTaskOrganizer);
mPipTaskOrganizer.registerPipTransitionCallback(this);
mActivityTaskManager = ActivityTaskManager.getService();
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
@@ -267,7 +278,6 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
try {
WindowManagerWrapper.getInstance().addPinnedStackListener(mPinnedStackListener);
- mPipTaskOrganizer.registerOrganizer(WINDOWING_MODE_PINNED);
} catch (RemoteException | UnsupportedOperationException e) {
Log.e(TAG, "Failed to register pinned stack listener", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index 255ba1b61db1..e57478eb0988 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -57,7 +57,8 @@ class PrivacyItemController @Inject constructor(
@VisibleForTesting
internal companion object {
val OPS_MIC_CAMERA = intArrayOf(AppOpsManager.OP_CAMERA,
- AppOpsManager.OP_RECORD_AUDIO)
+ AppOpsManager.OP_PHONE_CALL_CAMERA, AppOpsManager.OP_RECORD_AUDIO,
+ AppOpsManager.OP_PHONE_CALL_MICROPHONE)
val OPS_LOCATION = intArrayOf(
AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION)
@@ -248,9 +249,11 @@ class PrivacyItemController @Inject constructor(
private fun toPrivacyItem(appOpItem: AppOpItem): PrivacyItem? {
val type: PrivacyType = when (appOpItem.code) {
+ AppOpsManager.OP_PHONE_CALL_CAMERA,
AppOpsManager.OP_CAMERA -> PrivacyType.TYPE_CAMERA
- AppOpsManager.OP_COARSE_LOCATION -> PrivacyType.TYPE_LOCATION
+ AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION -> PrivacyType.TYPE_LOCATION
+ AppOpsManager.OP_PHONE_CALL_MICROPHONE,
AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE
else -> return null
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index 0347867b61fc..1a7e2290e044 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -38,7 +38,7 @@ import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.phone.StatusBar;
import java.util.Optional;
@@ -56,7 +56,7 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation {
private final static String TAG = "OverviewProxyRecentsImpl";
@Nullable
private final Lazy<StatusBar> mStatusBarLazy;
- private final Optional<Divider> mDividerOptional;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private Context mContext;
private Handler mHandler;
@@ -66,9 +66,9 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation {
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
public OverviewProxyRecentsImpl(Optional<Lazy<StatusBar>> statusBarLazy,
- Optional<Divider> dividerOptional) {
+ Optional<SplitScreen> splitScreenOptional) {
mStatusBarLazy = statusBarLazy.orElse(null);
- mDividerOptional = dividerOptional;
+ mSplitScreenOptional = splitScreenOptional;
}
@Override
@@ -163,12 +163,12 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation {
if (runningTask.supportsSplitScreenMultiWindow) {
if (ActivityManagerWrapper.getInstance().setTaskWindowingModeSplitScreenPrimary(
runningTask.id, stackCreateMode, initialBounds)) {
- mDividerOptional.ifPresent(Divider::onDockedTopTask);
-
- // The overview service is handling split screen, so just skip the wait for the
- // first draw and notify the divider to start animating now
- mDividerOptional.ifPresent(Divider::onRecentsDrawn);
-
+ mSplitScreenOptional.ifPresent(splitScreen -> {
+ splitScreen.onDockedTopTask();
+ // The overview service is handling split screen, so just skip the wait
+ // for the first draw and notify the divider to start animating now
+ splitScreen.onRecentsDrawn();
+ });
return true;
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index e931a6bf179a..c0cc58638e3f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -86,7 +86,7 @@ import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -123,7 +123,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
private final Context mContext;
private final PipUI mPipUI;
private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
- private final Optional<Divider> mDividerOptional;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private SysUiState mSysUiState;
private final Handler mHandler;
private final Lazy<NavigationBarController> mNavBarControllerLazy;
@@ -232,7 +232,9 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
long token = Binder.clearCallingIdentity();
try {
- mDividerOptional.ifPresent(Divider::onDockedFirstAnimationFrame);
+ mSplitScreenOptional.ifPresent(splitScreen -> {
+ splitScreen.onDockedFirstAnimationFrame();
+ });
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -262,8 +264,8 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
long token = Binder.clearCallingIdentity();
try {
- return mDividerOptional.map(
- divider -> divider.getView().getNonMinimizedSplitScreenSecondaryBounds())
+ return mSplitScreenOptional.map(splitScreen ->
+ splitScreen.getDividerView().getNonMinimizedSplitScreenSecondaryBounds())
.orElse(null);
} finally {
Binder.restoreCallingIdentity(token);
@@ -399,10 +401,8 @@ public class OverviewProxyService extends CurrentUserTracker implements
@Override
public void setSplitScreenMinimized(boolean minimized) {
- Divider divider = mDividerOptional.get();
- if (divider != null) {
- divider.setMinimized(minimized);
- }
+ mSplitScreenOptional.ifPresent(
+ splitScreen -> splitScreen.setMinimized(minimized));
}
@Override
@@ -602,7 +602,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
public OverviewProxyService(Context context, CommandQueue commandQueue,
Lazy<NavigationBarController> navBarControllerLazy, NavigationModeController navModeController,
NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
- PipUI pipUI, Optional<Divider> dividerOptional,
+ PipUI pipUI, Optional<SplitScreen> splitScreenOptional,
Optional<Lazy<StatusBar>> statusBarOptionalLazy, OneHandedUI oneHandedUI,
BroadcastDispatcher broadcastDispatcher) {
super(broadcastDispatcher);
@@ -613,7 +613,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
mNavBarControllerLazy = navBarControllerLazy;
mStatusBarWinController = statusBarWinController;
mConnectionBackoffAttempts = 0;
- mDividerOptional = dividerOptional;
+ mSplitScreenOptional = splitScreenOptional;
mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
com.android.internal.R.string.config_recentsComponentName));
mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
@@ -755,10 +755,8 @@ public class OverviewProxyService extends CurrentUserTracker implements
startConnectionToCurrentUser();
// Clean up the minimized state if launcher dies
- Divider divider = mDividerOptional.get();
- if (divider != null) {
- divider.setMinimized(false);
- }
+ mSplitScreenOptional.ifPresent(
+ splitScreen -> splitScreen.setMinimized(false));
}
public void startConnectionToCurrentUser() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
index 1d29ac629cd8..a641730ac64e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
@@ -35,7 +35,6 @@ public interface RecentsImplementation {
default void showRecentApps(boolean triggeredFromAltTab) {}
default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {}
default void toggleRecentApps() {}
- default void growRecents() {}
default boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,
int metricsDockAction) {
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 469c4a7b4c57..8ec3db59117d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -21,7 +21,6 @@ import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -70,7 +69,6 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
private static final String ACTION_STOP_NOTIF =
"com.android.systemui.screenrecord.STOP_FROM_NOTIF";
private static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE";
- private static final String ACTION_DELETE = "com.android.systemui.screenrecord.DELETE";
private final RecordingController mController;
private final KeyguardDismissUtil mKeyguardDismissUtil;
@@ -184,25 +182,6 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
// Close quick shade
sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
break;
- case ACTION_DELETE:
- mKeyguardDismissUtil.executeWhenUnlocked(() -> {
- // Close quick shade
- sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
- ContentResolver resolver = getContentResolver();
- Uri uri = Uri.parse(intent.getStringExtra(EXTRA_PATH));
- resolver.delete(uri, null, null);
-
- Toast.makeText(
- this,
- R.string.screenrecord_delete_description,
- Toast.LENGTH_LONG).show();
- Log.d(TAG, "Deleted recording " + uri);
-
- // Remove notification
- mNotificationManager.cancelAsUser(null, NOTIFICATION_VIEW_ID, currentUser);
- return false;
- }, false);
- break;
}
return Service.START_STICKY;
}
@@ -312,16 +291,6 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
.build();
- Notification.Action deleteAction = new Notification.Action.Builder(
- Icon.createWithResource(this, R.drawable.ic_screenrecord),
- getResources().getString(R.string.screenrecord_delete_label),
- PendingIntent.getService(
- this,
- REQUEST_CODE,
- getDeleteIntent(this, uri.toString()),
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
- .build();
-
Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
getResources().getString(R.string.screenrecord_name));
@@ -335,7 +304,6 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
viewIntent,
PendingIntent.FLAG_IMMUTABLE))
.addAction(shareAction)
- .addAction(deleteAction)
.setAutoCancel(true)
.addExtras(extras);
@@ -414,11 +382,6 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
.putExtra(EXTRA_PATH, path);
}
- private static Intent getDeleteIntent(Context context, String path) {
- return new Intent(context, RecordingService.class).setAction(ACTION_DELETE)
- .putExtra(EXTRA_PATH, path);
- }
-
@Override
public void onInfo(MediaRecorder mr, int what, int extra) {
Log.d(TAG, "Media recorder info: " + what);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
index 20fa991dcc1f..6b42f2e07bc3 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
@@ -22,6 +22,7 @@ import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_CHORD;
import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_OTHER;
import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER;
import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OVERVIEW;
+import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_VENDOR_GESTURE;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
@@ -37,6 +38,8 @@ public enum ScreenshotEvent implements UiEventLogger.UiEventEnum {
SCREENSHOT_REQUESTED_OVERVIEW(304),
@UiEvent(doc = "screenshot requested from accessibility actions")
SCREENSHOT_REQUESTED_ACCESSIBILITY_ACTIONS(382),
+ @UiEvent(doc = "screenshot requested from vendor gesture")
+ SCREENSHOT_REQUESTED_VENDOR_GESTURE(638),
@UiEvent(doc = "screenshot requested (other)")
SCREENSHOT_REQUESTED_OTHER(305),
@UiEvent(doc = "screenshot was saved")
@@ -81,6 +84,8 @@ public enum ScreenshotEvent implements UiEventLogger.UiEventEnum {
return ScreenshotEvent.SCREENSHOT_REQUESTED_OVERVIEW;
case SCREENSHOT_ACCESSIBILITY_ACTIONS:
return ScreenshotEvent.SCREENSHOT_REQUESTED_ACCESSIBILITY_ACTIONS;
+ case SCREENSHOT_VENDOR_GESTURE:
+ return ScreenshotEvent.SCREENSHOT_REQUESTED_VENDOR_GESTURE;
case SCREENSHOT_OTHER:
default:
return ScreenshotEvent.SCREENSHOT_REQUESTED_OTHER;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
new file mode 100644
index 000000000000..91ef3c360186
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.screenshot.dagger;
+
+import android.app.Service;
+
+import com.android.systemui.screenshot.TakeScreenshotService;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
+
+/**
+ * Defines injectable resources for Screenshots
+ */
+@Module
+public abstract class ScreenshotModule {
+
+ /** */
+ @Binds
+ @IntoMap
+ @ClassKey(TakeScreenshotService.class)
+ public abstract Service bindTakeScreenshotService(TakeScreenshotService service);
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index ee3303bf33ef..0d92d1e198e7 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -30,8 +30,10 @@ import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.recents.Recents;
-import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.DividerView;
+import com.android.systemui.stackdivider.SplitScreen;
+
+import java.util.Optional;
import javax.inject.Inject;
@@ -43,7 +45,7 @@ public class ShortcutKeyDispatcher extends SystemUI
implements ShortcutKeyServiceProxy.Callbacks {
private static final String TAG = "ShortcutKeyDispatcher";
- private final Divider mDivider;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private final Recents mRecents;
private ShortcutKeyServiceProxy mShortcutKeyServiceProxy = new ShortcutKeyServiceProxy(this);
@@ -58,14 +60,16 @@ public class ShortcutKeyDispatcher extends SystemUI
protected final long SC_DOCK_RIGHT = META_MASK | KeyEvent.KEYCODE_RIGHT_BRACKET;
@Inject
- public ShortcutKeyDispatcher(Context context, Divider divider, Recents recents) {
+ public ShortcutKeyDispatcher(Context context,
+ Optional<SplitScreen> splitScreenOptional, Recents recents) {
super(context);
- mDivider = divider;
+ mSplitScreenOptional = splitScreenOptional;
mRecents = recents;
}
/**
* Registers a shortcut key to window manager.
+ *
* @param shortcutCode packed representation of shortcut key code and meta information
*/
public void registerShortcutKey(long shortcutCode) {
@@ -92,24 +96,28 @@ public class ShortcutKeyDispatcher extends SystemUI
}
private void handleDockKey(long shortcutCode) {
- if (mDivider == null || !mDivider.isDividerVisible()) {
- // Split the screen
- mRecents.splitPrimaryTask((shortcutCode == SC_DOCK_LEFT)
- ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
- : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, null, -1);
- } else {
- // If there is already a docked window, we respond by resizing the docking pane.
- DividerView dividerView = mDivider.getView();
- DividerSnapAlgorithm snapAlgorithm = dividerView.getSnapAlgorithm();
- int dividerPosition = dividerView.getCurrentPosition();
- DividerSnapAlgorithm.SnapTarget currentTarget =
- snapAlgorithm.calculateNonDismissingSnapTarget(dividerPosition);
- DividerSnapAlgorithm.SnapTarget target = (shortcutCode == SC_DOCK_LEFT)
- ? snapAlgorithm.getPreviousTarget(currentTarget)
- : snapAlgorithm.getNextTarget(currentTarget);
- dividerView.startDragging(true /* animate */, false /* touching */);
- dividerView.stopDragging(target.position, 0f, false /* avoidDismissStart */,
- true /* logMetrics */);
+ if (mSplitScreenOptional.isPresent()) {
+ SplitScreen splitScreen = mSplitScreenOptional.get();
+ if (splitScreen.isDividerVisible()) {
+ // If there is already a docked window, we respond by resizing the docking pane.
+ DividerView dividerView = splitScreen.getDividerView();
+ DividerSnapAlgorithm snapAlgorithm = dividerView.getSnapAlgorithm();
+ int dividerPosition = dividerView.getCurrentPosition();
+ DividerSnapAlgorithm.SnapTarget currentTarget =
+ snapAlgorithm.calculateNonDismissingSnapTarget(dividerPosition);
+ DividerSnapAlgorithm.SnapTarget target = (shortcutCode == SC_DOCK_LEFT)
+ ? snapAlgorithm.getPreviousTarget(currentTarget)
+ : snapAlgorithm.getNextTarget(currentTarget);
+ dividerView.startDragging(true /* animate */, false /* touching */);
+ dividerView.stopDragging(target.position, 0f, false /* avoidDismissStart */,
+ true /* logMetrics */);
+ return;
+ }
}
+
+ // Split the screen
+ mRecents.splitPrimaryTask((shortcutCode == SC_DOCK_LEFT)
+ ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
+ : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, null, -1);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
deleted file mode 100644
index e9c880ebbcc9..000000000000
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.systemui.stackdivider;
-
-import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.window.WindowContainerToken;
-
-import com.android.systemui.SystemUI;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.function.Consumer;
-
-/**
- * Controls the docked stack divider.
- */
-@SysUISingleton
-public class Divider extends SystemUI {
- private final KeyguardStateController mKeyguardStateController;
- private final DividerController mDividerController;
-
- Divider(Context context, DividerController dividerController,
- KeyguardStateController keyguardStateController) {
- super(context);
- mDividerController = dividerController;
- mKeyguardStateController = keyguardStateController;
- }
-
- @Override
- public void start() {
- mDividerController.start();
- // Hide the divider when keyguard is showing. Even though keyguard/statusbar is above
- // everything, it is actually transparent except for notifications, so we still need to
- // hide any surfaces that are below it.
- // TODO(b/148906453): Figure out keyguard dismiss animation for divider view.
- mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
- @Override
- public void onKeyguardShowingChanged() {
- mDividerController.onKeyguardShowingChanged(mKeyguardStateController.isShowing());
- }
- });
- // Don't initialize the divider or anything until we get the default display.
-
- ActivityManagerWrapper.getInstance().registerTaskStackListener(
- new TaskStackChangeListener() {
- @Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
- if (!wasVisible || task.configuration.windowConfiguration.getWindowingMode()
- != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || !mDividerController.isSplitScreenSupported()) {
- return;
- }
-
- if (mDividerController.isMinimized()) {
- onUndockingTask();
- }
- }
-
- @Override
- public void onActivityForcedResizable(String packageName, int taskId,
- int reason) {
- mDividerController.onActivityForcedResizable(packageName, taskId, reason);
- }
-
- @Override
- public void onActivityDismissingDockedStack() {
- mDividerController.onActivityDismissingSplitScreen();
- }
-
- @Override
- public void onActivityLaunchOnSecondaryDisplayFailed() {
- mDividerController.onActivityLaunchOnSecondaryDisplayFailed();
- }
- }
- );
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- mDividerController.dump(pw);
- }
-
- /** Switch to minimized state if appropriate. */
- public void setMinimized(final boolean minimized) {
- mDividerController.setMinimized(minimized);
- }
-
- public boolean isMinimized() {
- return mDividerController.isMinimized();
- }
-
- public boolean isHomeStackResizable() {
- return mDividerController.isHomeStackResizable();
- }
-
- /** Callback for undocking task. */
- public void onUndockingTask() {
- mDividerController.onUndockingTask();
- }
-
- public void onRecentsDrawn() {
- mDividerController.onRecentsDrawn();
- }
-
- public void onDockedFirstAnimationFrame() {
- mDividerController.onDockedFirstAnimationFrame();
- }
-
- public void onDockedTopTask() {
- mDividerController.onDockedTopTask();
- }
-
- public void onAppTransitionFinished() {
- mDividerController.onAppTransitionFinished();
- }
-
- public DividerView getView() {
- return mDividerController.getDividerView();
- }
-
- /** @return the container token for the secondary split root task. */
- public WindowContainerToken getSecondaryRoot() {
- return mDividerController.getSecondaryRoot();
- }
-
- /** Register a listener that gets called whenever the existence of the divider changes */
- public void registerInSplitScreenListener(Consumer<Boolean> listener) {
- mDividerController.registerInSplitScreenListener(listener);
- }
-
- /** {@code true} if this is visible */
- public boolean isDividerVisible() {
- return mDividerController.isDividerVisible();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
index c915f071297f..64ee7ed5e0e0 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
@@ -38,7 +38,7 @@ import com.android.wm.shell.common.TransactionPool;
class DividerImeController implements DisplayImeController.ImePositionProcessor {
private static final String TAG = "DividerImeController";
- private static final boolean DEBUG = DividerController.DEBUG;
+ private static final boolean DEBUG = SplitScreenController.DEBUG;
private static final float ADJUSTED_NONFOCUS_DIM = 0.3f;
@@ -100,15 +100,15 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
}
private DividerView getView() {
- return mSplits.mDividerController.getDividerView();
+ return mSplits.mSplitScreenController.getDividerView();
}
private SplitDisplayLayout getLayout() {
- return mSplits.mDividerController.getSplitLayout();
+ return mSplits.mSplitScreenController.getSplitLayout();
}
private boolean isDividerVisible() {
- return mSplits.mDividerController.isDividerVisible();
+ return mSplits.mSplitScreenController.isDividerVisible();
}
private boolean getSecondaryHasFocus(int displayId) {
@@ -151,7 +151,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
mSecondaryHasFocus = getSecondaryHasFocus(displayId);
final boolean targetAdjusted = splitIsVisible && imeShouldShow && mSecondaryHasFocus
&& !imeIsFloating && !getLayout().mDisplayLayout.isLandscape()
- && !mSplits.mDividerController.isMinimized();
+ && !mSplits.mSplitScreenController.isMinimized();
if (mLastAdjustTop < 0) {
mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
} else if (mLastAdjustTop != (imeShouldShow ? mShownTop : mHiddenTop)) {
@@ -236,7 +236,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
}
- if (!mSplits.mDividerController.getWmProxy().queueSyncTransactionIfWaiting(wct)) {
+ if (!mSplits.mSplitScreenController.getWmProxy().queueSyncTransactionIfWaiting(wct)) {
WindowOrganizer.applyTransaction(wct);
}
}
@@ -250,7 +250,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
: DisplayImeController.ANIMATION_DURATION_HIDE_MS);
}
}
- mSplits.mDividerController.setAdjustedForIme(mTargetShown && !mPaused);
+ mSplits.mSplitScreenController.setAdjustedForIme(mTargetShown && !mPaused);
}
public void updateAdjustForIme() {
@@ -402,7 +402,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
mTargetAdjusted = mPausedTargetAdjusted;
updateDimTargets();
final DividerView view = getView();
- if ((mTargetAdjusted != mAdjusted) && !mSplits.mDividerController.isMinimized()
+ if ((mTargetAdjusted != mAdjusted) && !mSplits.mSplitScreenController.isMinimized()
&& view != null) {
// End unminimize animations since they conflict with adjustment animations.
view.finishAnimations();
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
deleted file mode 100644
index 9c2139772e7d..000000000000
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.stackdivider;
-
-import android.content.Context;
-import android.os.Handler;
-
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.common.SystemWindows;
-import com.android.wm.shell.common.TransactionPool;
-
-import dagger.Module;
-import dagger.Provides;
-
-/**
- * Module which provides a Divider.
- */
-@Module
-public class DividerModule {
- @SysUISingleton
- @Provides
- static Divider provideDivider(Context context, DisplayController displayController,
- SystemWindows systemWindows, DisplayImeController imeController, @Main Handler handler,
- KeyguardStateController keyguardStateController, TransactionPool transactionPool) {
- // TODO(b/161116823): fetch DividerProxy from WM shell lib.
- DividerController dividerController = new DividerController(context, displayController,
- systemWindows, imeController, handler, transactionPool);
- return new Divider(context, dividerController, keyguardStateController);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index e5c02d6fc454..95f048b0b06d 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -76,7 +76,7 @@ import java.util.function.Consumer;
public class DividerView extends FrameLayout implements OnTouchListener,
OnComputeInternalInsetsListener {
private static final String TAG = "DividerView";
- private static final boolean DEBUG = DividerController.DEBUG;
+ private static final boolean DEBUG = SplitScreenController.DEBUG;
public interface DividerCallbacks {
void onDraggingStart();
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
index ff8bab07db05..4c26694cc22a 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -69,9 +69,9 @@ final class ForcedResizableInfoActivityController implements DividerView.Divider
}
public ForcedResizableInfoActivityController(Context context,
- DividerController dividerController) {
+ SplitScreenController splitScreenController) {
mContext = context;
- dividerController.registerInSplitScreenListener(mDockedStackExistsListener);
+ splitScreenController.registerInSplitScreenListener(mDockedStackExistsListener);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java
new file mode 100644
index 000000000000..91850cc46ab6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java
@@ -0,0 +1,86 @@
+/*
+ * 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.stackdivider;
+
+import android.window.WindowContainerToken;
+
+import java.io.PrintWriter;
+import java.util.function.Consumer;
+
+/**
+ * Interface to engage split screen feature.
+ */
+public interface SplitScreen {
+ /** Returns {@code true} if split screen is supported on the device. */
+ boolean isSplitScreenSupported();
+
+ /** Called when keyguard showing state changed. */
+ void onKeyguardVisibilityChanged(boolean isShowing);
+
+ /** Returns {@link DividerView}. */
+ DividerView getDividerView();
+
+ /** Returns {@code true} if one of the split screen is in minimized mode. */
+ boolean isMinimized();
+
+ /** Returns {@code true} if the home stack is resizable. */
+ boolean isHomeStackResizable();
+
+ /** Returns {@code true} if the divider is visible. */
+ boolean isDividerVisible();
+
+ /** Switch to minimized state if appropriate. */
+ void setMinimized(boolean minimized);
+
+ /**
+ * Workaround for b/62528361, at the time recents has drawn, it may happen before a
+ * configuration change to the Divider, and internally, the event will be posted to the
+ * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
+ * register the event handler here and proxy the event to the current DividerView.
+ */
+ void onRecentsDrawn();
+
+ /** Called when there's an activity forced resizable. */
+ void onActivityForcedResizable(String packageName, int taskId, int reason);
+
+ /** Called when there's an activity dismissing split screen. */
+ void onActivityDismissingSplitScreen();
+
+ /** Called when there's an activity launch on secondary display failed. */
+ void onActivityLaunchOnSecondaryDisplayFailed();
+
+ /** Called when there's a task undocking. */
+ void onUndockingTask();
+
+ /** Called when the first docked animation frame rendered. */
+ void onDockedFirstAnimationFrame();
+
+ /** Called when top task docked. */
+ void onDockedTopTask();
+
+ /** Called when app transition finished. */
+ void onAppTransitionFinished();
+
+ /** Dumps current status of Split Screen. */
+ void dump(PrintWriter pw);
+
+ /** Registers listener that gets called whenever the existence of the divider changes. */
+ void registerInSplitScreenListener(Consumer<Boolean> listener);
+
+ /** @return the container token for the secondary split root task. */
+ WindowContainerToken getSecondaryRoot();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java
index 1ee8abb411b9..11773f6d358c 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java
@@ -35,6 +35,7 @@ import android.window.WindowOrganizer;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.systemui.R;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
@@ -48,26 +49,34 @@ import java.util.ArrayList;
import java.util.function.Consumer;
/**
- * Controls the docked stack divider.
+ * Controls split screen feature.
*/
-public class DividerController implements DisplayController.OnDisplaysChangedListener {
+public class SplitScreenController implements SplitScreen,
+ DisplayController.OnDisplaysChangedListener {
static final boolean DEBUG = false;
+
private static final String TAG = "Divider";
+ private static final int DEFAULT_APP_TRANSITION_DURATION = 336;
+
+ private final Context mContext;
+ private final DisplayChangeController.OnDisplayChangingListener mRotationController;
+ private final DisplayController mDisplayController;
+ private final DisplayImeController mImeController;
+ private final DividerImeController mImePositionProcessor;
+ private final DividerState mDividerState = new DividerState();
+ private final ForcedResizableInfoActivityController mForcedResizableController;
+ private final Handler mHandler;
+ private final SplitScreenTaskOrganizer mSplits;
+ private final SystemWindows mSystemWindows;
+ final TransactionPool mTransactionPool;
+ private final WindowManagerProxy mWindowManagerProxy;
+
+ private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
+ new ArrayList<>();
- static final int DEFAULT_APP_TRANSITION_DURATION = 336;
private DividerWindowManager mWindowManager;
private DividerView mView;
- private final DividerState mDividerState = new DividerState();
- private boolean mVisible = false;
- private boolean mMinimized = false;
- private boolean mAdjustedForIme = false;
- private boolean mHomeStackResizable = false;
- private ForcedResizableInfoActivityController mForcedResizableController;
- private SystemWindows mSystemWindows;
- private DisplayController mDisplayController;
- private DisplayImeController mImeController;
- final TransactionPool mTransactionPool;
// Keeps track of real-time split geometry including snap positions and ime adjustments
private SplitDisplayLayout mSplitLayout;
@@ -77,21 +86,16 @@ public class DividerController implements DisplayController.OnDisplaysChangedLis
// layout that we sent back to WM.
private SplitDisplayLayout mRotateSplitLayout;
- private final Handler mHandler;
- private final WindowManagerProxy mWindowManagerProxy;
-
- private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
- new ArrayList<>();
-
- private final SplitScreenTaskOrganizer mSplits;
- private final DisplayChangeController.OnDisplayChangingListener mRotationController;
- private final DividerImeController mImePositionProcessor;
- private final Context mContext;
private boolean mIsKeyguardShowing;
+ private boolean mVisible = false;
+ private boolean mMinimized = false;
+ private boolean mAdjustedForIme = false;
+ private boolean mHomeStackResizable = false;
- public DividerController(Context context,
+ public SplitScreenController(Context context,
DisplayController displayController, SystemWindows systemWindows,
- DisplayImeController imeController, Handler handler, TransactionPool transactionPool) {
+ DisplayImeController imeController, Handler handler, TransactionPool transactionPool,
+ ShellTaskOrganizer shellTaskOrganizer) {
mContext = context;
mDisplayController = displayController;
mSystemWindows = systemWindows;
@@ -100,7 +104,7 @@ public class DividerController implements DisplayController.OnDisplaysChangedLis
mForcedResizableController = new ForcedResizableInfoActivityController(context, this);
mTransactionPool = transactionPool;
mWindowManagerProxy = new WindowManagerProxy(mTransactionPool, mHandler);
- mSplits = new SplitScreenTaskOrganizer(this);
+ mSplits = new SplitScreenTaskOrganizer(this, shellTaskOrganizer);
mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler);
mRotationController =
(display, fromRotation, toRotation, wct) -> {
@@ -140,10 +144,7 @@ public class DividerController implements DisplayController.OnDisplaysChangedLis
wct.merge(t, true /* transfer */);
}
};
- }
- /** Inits the divider service. */
- public void start() {
mWindowManager = new DividerWindowManager(mSystemWindows);
mDisplayController.addDisplayWindowListener(this);
// Don't initialize the divider or anything until we get the default display.
@@ -155,15 +156,15 @@ public class DividerController implements DisplayController.OnDisplaysChangedLis
}
/** Called when keyguard showing state changed. */
- public void onKeyguardShowingChanged(boolean isShowing) {
+ public void onKeyguardVisibilityChanged(boolean showing) {
if (!isSplitActive() || mView == null) {
return;
}
- mView.setHidden(isShowing);
- if (!isShowing) {
+ mView.setHidden(showing);
+ if (!showing) {
mImePositionProcessor.updateAdjustForIme();
}
- mIsKeyguardShowing = isShowing;
+ mIsKeyguardShowing = showing;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index ef5e8a15882c..325c5597f9d8 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -33,9 +33,13 @@ import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.window.TaskOrganizer;
-class SplitScreenTaskOrganizer extends TaskOrganizer {
+import com.android.wm.shell.ShellTaskOrganizer;
+
+class SplitScreenTaskOrganizer implements ShellTaskOrganizer.TaskListener {
private static final String TAG = "SplitScreenTaskOrg";
- private static final boolean DEBUG = DividerController.DEBUG;
+ private static final boolean DEBUG = SplitScreenController.DEBUG;
+
+ private final ShellTaskOrganizer mTaskOrganizer;
RunningTaskInfo mPrimary;
RunningTaskInfo mSecondary;
@@ -44,18 +48,20 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
SurfaceControl mPrimaryDim;
SurfaceControl mSecondaryDim;
Rect mHomeBounds = new Rect();
- final DividerController mDividerController;
+ final SplitScreenController mSplitScreenController;
private boolean mSplitScreenSupported = false;
final SurfaceSession mSurfaceSession = new SurfaceSession();
- SplitScreenTaskOrganizer(DividerController dividerController) {
- mDividerController = dividerController;
+ SplitScreenTaskOrganizer(SplitScreenController splitScreenController,
+ ShellTaskOrganizer shellTaskOrganizer) {
+ mSplitScreenController = splitScreenController;
+ mTaskOrganizer = shellTaskOrganizer;
+ mTaskOrganizer.addListener(this, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
}
void init() throws RemoteException {
- registerOrganizer(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- registerOrganizer(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
synchronized (this) {
try {
mPrimary = TaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY,
@@ -64,7 +70,7 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
} catch (Exception e) {
// teardown to prevent callbacks
- unregisterOrganizer();
+ mTaskOrganizer.removeListener(this);
throw e;
}
}
@@ -75,11 +81,11 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
}
SurfaceControl.Transaction getTransaction() {
- return mDividerController.mTransactionPool.acquire();
+ return mSplitScreenController.mTransactionPool.acquire();
}
void releaseTransaction(SurfaceControl.Transaction t) {
- mDividerController.mTransactionPool.release(t);
+ mSplitScreenController.mTransactionPool.release(t);
}
@Override
@@ -140,7 +146,7 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
t.apply();
releaseTransaction(t);
- mDividerController.onTaskVanished();
+ mSplitScreenController.onTaskVanished();
}
}
}
@@ -150,7 +156,7 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
if (taskInfo.displayId != DEFAULT_DISPLAY) {
return;
}
- mDividerController.post(() -> handleTaskInfoChanged(taskInfo));
+ mSplitScreenController.post(() -> handleTaskInfoChanged(taskInfo));
}
/**
@@ -169,7 +175,7 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
}
final boolean secondaryImpliedMinimize = mSecondary.topActivityType == ACTIVITY_TYPE_HOME
|| (mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS
- && mDividerController.isHomeStackResizable());
+ && mSplitScreenController.isHomeStackResizable());
final boolean primaryWasEmpty = mPrimary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
final boolean secondaryWasEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
if (info.token.asBinder() == mPrimary.token.asBinder()) {
@@ -181,7 +187,7 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
final boolean secondaryIsEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
final boolean secondaryImpliesMinimize = mSecondary.topActivityType == ACTIVITY_TYPE_HOME
|| (mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS
- && mDividerController.isHomeStackResizable());
+ && mSplitScreenController.isHomeStackResizable());
if (DEBUG) {
Log.d(TAG, "onTaskInfoChanged " + mPrimary + " " + mSecondary);
}
@@ -197,14 +203,14 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
Log.d(TAG, " at-least one split empty " + mPrimary.topActivityType
+ " " + mSecondary.topActivityType);
}
- if (mDividerController.isDividerVisible()) {
+ if (mSplitScreenController.isDividerVisible()) {
// Was in split-mode, which means we are leaving split, so continue that.
// This happens when the stack in the primary-split is dismissed.
if (DEBUG) {
Log.d(TAG, " was in split, so this means leave it "
+ mPrimary.topActivityType + " " + mSecondary.topActivityType);
}
- mDividerController.startDismissSplit();
+ mSplitScreenController.startDismissSplit();
} else if (!primaryIsEmpty && primaryWasEmpty && secondaryWasEmpty) {
// Wasn't in split-mode (both were empty), but now that the primary split is
// populated, we should fully enter split by moving everything else into secondary.
@@ -213,15 +219,15 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
if (DEBUG) {
Log.d(TAG, " was not in split, but primary is populated, so enter it");
}
- mDividerController.startEnterSplit();
+ mSplitScreenController.startEnterSplit();
}
} else if (secondaryImpliesMinimize) {
// Both splits are populated but the secondary split has a home/recents stack on top,
// so enter minimized mode.
- mDividerController.ensureMinimizedSplit();
+ mSplitScreenController.ensureMinimizedSplit();
} else {
// Both splits are populated by normal activities, so make sure we aren't minimized.
- mDividerController.ensureNormalSplit();
+ mSplitScreenController.ensureNormalSplit();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
index f2500e59abab..13ed02e9513e 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
@@ -33,7 +33,7 @@ import java.util.ArrayList;
* Helper for serializing sync-transactions and corresponding callbacks.
*/
class SyncTransactionQueue {
- private static final boolean DEBUG = DividerController.DEBUG;
+ private static final boolean DEBUG = SplitScreenController.DEBUG;
private static final String TAG = "SyncTransactionQueue";
// Just a little longer than the sync-engine timeout of 5s
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index 1079f10497a9..17bf346fa22b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -55,14 +55,6 @@ public interface NotificationPresenter extends ExpandableNotificationRow.OnExpan
void updateNotificationViews(String reason);
/**
- * Returns the maximum number of notifications to show while locked.
- *
- * @param recompute whether something has changed that means we should recompute this value
- * @return the maximum number of notifications to show while locked
- */
- int getMaxNotificationsWhileLocked(boolean recompute);
-
- /**
* Called when the row states are updated by {@link NotificationViewHierarchyManager}.
*/
void onUpdateRowStates();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
index 1fd0b03a77b7..24515f7bc210 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
@@ -164,6 +164,13 @@ public interface NotificationShadeWindowController extends RemoteInputController
default void setRequestTopUi(boolean requestTopUi, String componentTag) {}
/**
+ * Under low light conditions, we might want to increase the display brightness on devices that
+ * don't have an IR camera.
+ * @param brightness float from 0 to 1 or {@code LayoutParams.BRIGHTNESS_OVERRIDE_NONE}
+ */
+ default void setFaceAuthDisplayBrightness(float brightness) {}
+
+ /**
* Custom listener to pipe data back to plugins about whether or not the status bar would be
* collapsed if not for the plugin.
* TODO: Find cleaner way to do this.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java
index 77abcfa848ee..1e935c19b710 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java
@@ -85,6 +85,10 @@ public class NotificationShelfController {
return mView.getShelfIcons();
}
+ public @View.Visibility int getVisibility() {
+ return mView.getVisibility();
+ };
+
public void setCollapsedIcons(NotificationIconContainer notificationIcons) {
mView.setCollapsedIcons(notificationIcons);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 1cd1b60ac1ac..852c05547e32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -420,11 +420,6 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
int visibleNotifications = 0;
boolean onKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
- int maxNotifications = -1;
- if (onKeyguard && !mBypassController.getBypassEnabled()) {
- maxNotifications = mPresenter.getMaxNotificationsWhileLocked(true /* recompute */);
- }
- mListContainer.setMaxDisplayedNotifications(maxNotifications);
Stack<ExpandableNotificationRow> stack = new Stack<>();
for (int i = N - 1; i >= 0; i--) {
View child = mListContainer.getContainerChildAt(i);
@@ -439,8 +434,6 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
boolean isChildNotification =
mGroupManager.isChildInGroupWithSummary(entry.getSbn());
- row.setOnKeyguard(onKeyguard);
-
if (!onKeyguard) {
// If mAlwaysExpandNonGroupedNotification is false, then only expand the
// very first notification and if it's not a child of grouped notifications.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index ea614fb210b3..838cf0c9a6d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -55,12 +55,13 @@ import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.UiBackground;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.NotificationChannels;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -80,13 +81,13 @@ public class InstantAppNotifier extends SystemUI
private final CommandQueue mCommandQueue;
private boolean mDockedStackExists;
private KeyguardStateController mKeyguardStateController;
- private final Divider mDivider;
+ private final Optional<SplitScreen> mSplitScreenOptional;
@Inject
public InstantAppNotifier(Context context, CommandQueue commandQueue,
- @UiBackground Executor uiBgExecutor, Divider divider) {
+ @UiBackground Executor uiBgExecutor, Optional<SplitScreen> splitScreenOptional) {
super(context);
- mDivider = divider;
+ mSplitScreenOptional = splitScreenOptional;
mCommandQueue = commandQueue;
mUiBgExecutor = uiBgExecutor;
}
@@ -105,11 +106,11 @@ public class InstantAppNotifier extends SystemUI
mCommandQueue.addCallback(this);
mKeyguardStateController.addCallback(this);
- mDivider.registerInSplitScreenListener(
- exists -> {
+ mSplitScreenOptional.ifPresent(splitScreen ->
+ splitScreen.registerInSplitScreenListener(exists -> {
mDockedStackExists = exists;
updateForegroundInstantApps();
- });
+ }));
// Clear out all old notifications on startup (only present in the case where sysui dies)
NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
index 17e62890aadd..3bfdf5caa9b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
@@ -16,9 +16,9 @@
package com.android.systemui.statusbar.notification.collection
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection
/**
* Stores the state that [ShadeListBuilder] assigns to this [ListEntry]
@@ -35,7 +35,6 @@ data class ListAttachState private constructor(
* parent's section. Null if not attached to the list.
*/
var section: NotifSection?,
- var sectionIndex: Int,
/**
* If a [NotifFilter] is excluding this entry from the list, then that filter. Always null for
@@ -60,7 +59,6 @@ data class ListAttachState private constructor(
fun clone(other: ListAttachState) {
parent = other.parent
section = other.section
- sectionIndex = other.sectionIndex
excludingFilter = other.excludingFilter
promoter = other.promoter
suppressedChanges.clone(other.suppressedChanges)
@@ -70,7 +68,6 @@ data class ListAttachState private constructor(
fun reset() {
parent = null
section = null
- sectionIndex = -1
excludingFilter = null
promoter = null
suppressedChanges.reset()
@@ -82,7 +79,6 @@ data class ListAttachState private constructor(
return ListAttachState(
null,
null,
- -1,
null,
null,
SuppressedAttachState.create())
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
index 786c97d03712..52c5c3e08118 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
@@ -112,11 +112,9 @@ public class ListDumper {
.append(")");
}
- if (entry.getNotifSection() != null) {
- sb.append(" sectionIndex=")
- .append(entry.getSection())
- .append(" sectionName=")
- .append(entry.getNotifSection().getName());
+ if (entry.getSection() != null) {
+ sb.append(" section=")
+ .append(entry.getSection().getLabel());
}
if (includeRecordKeeping) {
@@ -175,12 +173,9 @@ public class ListDumper {
}
if (notifEntry.getAttachState().getSuppressedChanges().getSection() != null) {
- rksb.append("suppressedSectionIndex=")
+ rksb.append("suppressedSection=")
.append(notifEntry.getAttachState().getSuppressedChanges()
- .getSectionIndex())
- .append(" sectionName=")
- .append(notifEntry.getAttachState().getSuppressedChanges()
- .getSection().getName())
+ .getSection())
.append(" ");
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
index 65f5dc4e5f7c..82c1f243dcdb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
@@ -21,7 +21,7 @@ import android.annotation.UptimeMillisLong;
import androidx.annotation.Nullable;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection;
/**
* Abstract superclass for top-level entries, i.e. things that can appear in the final notification
@@ -78,13 +78,12 @@ public abstract class ListEntry {
return mPreviousAttachState.getParent();
}
- /** The section this notification was assigned to (0 to N-1, where N is number of sections). */
- public int getSection() {
- return mAttachState.getSectionIndex();
+ @Nullable public NotifSection getSection() {
+ return mAttachState.getSection();
}
- @Nullable public NotifSection getNotifSection() {
- return mAttachState.getSection();
+ public int getSectionIndex() {
+ return mAttachState.getSection() != null ? mAttachState.getSection().getIndex() : -1;
}
ListAttachState getAttachState() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
index 05dd4df1f2ce..a1844ff5d221 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
@@ -24,7 +24,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.OnBefo
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
@@ -155,10 +155,10 @@ public class NotifPipeline implements CommonNotifCollection {
* Sections that are used to sort top-level entries. If two entries have the same section,
* NotifComparators are consulted. Sections from this list are called in order for each
* notification passed through the pipeline. The first NotifSection to return true for
- * {@link NotifSection#isInSection(ListEntry)} sets the entry as part of its Section.
+ * {@link NotifSectioner#isInSection(ListEntry)} sets the entry as part of its Section.
*/
- public void setSections(List<NotifSection> sections) {
- mShadeListBuilder.setSections(sections);
+ public void setSections(List<NotifSectioner> sections) {
+ mShadeListBuilder.setSectioners(sections);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 6cbebf803511..2b545c56c8bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -28,10 +28,11 @@ import static com.android.systemui.statusbar.notification.collection.listbuilder
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_SORTING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_TRANSFORMING;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.MainThread;
import android.annotation.Nullable;
import android.util.ArrayMap;
-import android.util.Pair;
import androidx.annotation.NonNull;
@@ -39,6 +40,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.NotificationInteractionTracker;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
@@ -48,7 +50,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.ShadeL
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
@@ -119,6 +121,8 @@ public class ShadeListBuilder implements Dumpable {
mLogger = logger;
mInteractionTracker = interactionTracker;
dumpManager.registerDumpable(TAG, this);
+
+ setSectioners(Collections.emptyList());
}
/**
@@ -193,15 +197,17 @@ public class ShadeListBuilder implements Dumpable {
promoter.setInvalidationListener(this::onPromoterInvalidated);
}
- void setSections(List<NotifSection> sections) {
+ void setSectioners(List<NotifSectioner> sectioners) {
Assert.isMainThread();
mPipelineState.requireState(STATE_IDLE);
mNotifSections.clear();
- for (NotifSection section : sections) {
- mNotifSections.add(section);
- section.setInvalidationListener(this::onNotifSectionInvalidated);
+ for (NotifSectioner sectioner : sectioners) {
+ mNotifSections.add(new NotifSection(sectioner, mNotifSections.size()));
+ sectioner.setInvalidationListener(this::onNotifSectionInvalidated);
}
+
+ mNotifSections.add(new NotifSection(DEFAULT_SECTIONER, mNotifSections.size()));
}
void setNotifStabilityManager(NotifStabilityManager notifStabilityManager) {
@@ -275,7 +281,7 @@ public class ShadeListBuilder implements Dumpable {
rebuildListIfBefore(STATE_TRANSFORMING);
}
- private void onNotifSectionInvalidated(NotifSection section) {
+ private void onNotifSectionInvalidated(NotifSectioner section) {
Assert.isMainThread();
mLogger.logNotifSectionInvalidated(section.getName(), mPipelineState.getState());
@@ -652,7 +658,6 @@ public class ShadeListBuilder implements Dumpable {
*/
private void annulAddition(ListEntry entry) {
entry.setParent(null);
- entry.getAttachState().setSectionIndex(-1);
entry.getAttachState().setSection(null);
entry.getAttachState().setPromoter(null);
if (entry.mFirstAddedIteration == mIterationCount) {
@@ -663,12 +668,12 @@ public class ShadeListBuilder implements Dumpable {
private void sortList() {
// Assign sections to top-level elements and sort their children
for (ListEntry entry : mNotifList) {
- Pair<NotifSection, Integer> sectionWithIndex = applySections(entry);
+ NotifSection section = applySections(entry);
if (entry instanceof GroupEntry) {
GroupEntry parent = (GroupEntry) entry;
for (NotificationEntry child : parent.getChildren()) {
- child.getAttachState().setSection(sectionWithIndex.first);
- child.getAttachState().setSectionIndex(sectionWithIndex.second);
+ child.getAttachState().setSection(section);
+ child.getAttachState().setSection(section);
}
parent.sortChildren(sChildComparator);
}
@@ -736,16 +741,13 @@ public class ShadeListBuilder implements Dumpable {
mLogger.logSectionChanged(
mIterationCount,
prev.getSection(),
- prev.getSectionIndex(),
- curr.getSection(),
- curr.getSectionIndex());
+ curr.getSection());
}
if (curr.getSuppressedChanges().getSection() != null) {
mLogger.logSectionChangeSuppressed(
mIterationCount,
curr.getSuppressedChanges().getSection(),
- curr.getSuppressedChanges().getSectionIndex(),
curr.getSection());
}
}
@@ -762,7 +764,10 @@ public class ShadeListBuilder implements Dumpable {
callOnCleanup(mNotifPromoters);
callOnCleanup(mNotifFinalizeFilters);
callOnCleanup(mNotifComparators);
- callOnCleanup(mNotifSections);
+
+ for (int i = 0; i < mNotifSections.size(); i++) {
+ mNotifSections.get(i).getSectioner().onCleanup();
+ }
if (mNotifStabilityManager != null) {
callOnCleanup(List.of(mNotifStabilityManager));
@@ -777,7 +782,9 @@ public class ShadeListBuilder implements Dumpable {
private final Comparator<ListEntry> mTopLevelComparator = (o1, o2) -> {
- int cmp = Integer.compare(o1.getSection(), o2.getSection());
+ int cmp = Integer.compare(
+ requireNonNull(o1.getSection()).getIndex(),
+ requireNonNull(o2.getSection()).getIndex());
if (cmp == 0) {
for (int i = 0; i < mNotifComparators.size(); i++) {
@@ -855,45 +862,41 @@ public class ShadeListBuilder implements Dumpable {
return null;
}
- private Pair<NotifSection, Integer> applySections(ListEntry entry) {
- Pair<NotifSection, Integer> sectionWithIndex = findSection(entry);
+ private NotifSection applySections(ListEntry entry) {
+ final NotifSection newSection = findSection(entry);
final ListAttachState prevAttachState = entry.getPreviousAttachState();
+ NotifSection finalSection = newSection;
+
// are we changing sections of this entry?
if (mNotifStabilityManager != null
&& prevAttachState.getParent() != null
- && (sectionWithIndex.first != prevAttachState.getSection()
- || sectionWithIndex.second != prevAttachState.getSectionIndex())) {
+ && newSection != prevAttachState.getSection()) {
// are section changes allowed?
- if (!mNotifStabilityManager.isSectionChangeAllowed(
- entry.getRepresentativeEntry())) {
- entry.getAttachState().getSuppressedChanges().setSection(
- sectionWithIndex.first);
- entry.getAttachState().getSuppressedChanges().setSectionIndex(
- sectionWithIndex.second);
+ if (!mNotifStabilityManager.isSectionChangeAllowed(entry.getRepresentativeEntry())) {
+ // record the section that we wanted to change to
+ entry.getAttachState().getSuppressedChanges().setSection(newSection);
// keep the previous section
- sectionWithIndex = new Pair(
- prevAttachState.getSection(),
- prevAttachState.getSectionIndex());
+ finalSection = prevAttachState.getSection();
}
}
- entry.getAttachState().setSection(sectionWithIndex.first);
- entry.getAttachState().setSectionIndex(sectionWithIndex.second);
+ entry.getAttachState().setSection(finalSection);
- return sectionWithIndex;
+ return finalSection;
}
- private Pair<NotifSection, Integer> findSection(ListEntry entry) {
+ @NonNull
+ private NotifSection findSection(ListEntry entry) {
for (int i = 0; i < mNotifSections.size(); i++) {
- NotifSection sectioner = mNotifSections.get(i);
- if (sectioner.isInSection(entry)) {
- return new Pair<>(sectioner, i);
+ NotifSection section = mNotifSections.get(i);
+ if (section.getSectioner().isInSection(entry)) {
+ return section;
}
}
- return new Pair<>(sDefaultSection, mNotifSections.size());
+ throw new RuntimeException("Missing default sectioner!");
}
private void rebuildListIfBefore(@PipelineState.StateName int state) {
@@ -963,15 +966,15 @@ public class ShadeListBuilder implements Dumpable {
void onRenderList(@NonNull List<ListEntry> entries);
}
- private static final NotifSection sDefaultSection =
- new NotifSection("UnknownSection") {
+ private static final NotifSectioner DEFAULT_SECTIONER =
+ new NotifSectioner("UnknownSection") {
@Override
public boolean isInSection(ListEntry entry) {
return true;
}
};
- private static final String TAG = "ShadeListBuilder";
-
private static final int MIN_CHILDREN_FOR_GROUP = 2;
+
+ private static final String TAG = "ShadeListBuilder";
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt
index 52612365712e..3eb2e610f329 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.notification.collection
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
/**
* Stores the suppressed state that [ShadeListBuilder] assigned to this [ListEntry] before the
@@ -33,22 +33,19 @@ data class SuppressedAttachState private constructor(
* The assigned section for this ListEntry. If the child of the group, this will be the
* parent's section. Null if not attached to the list.
*/
- var section: NotifSection?,
- var sectionIndex: Int
+ var section: NotifSection?
) {
/** Copies the state of another instance. */
fun clone(other: SuppressedAttachState) {
parent = other.parent
section = other.section
- sectionIndex = other.sectionIndex
}
/** Resets back to a "clean" state (the same as created by the factory method) */
fun reset() {
parent = null
section = null
- sectionIndex = -1
}
companion object {
@@ -56,8 +53,7 @@ data class SuppressedAttachState private constructor(
fun create(): SuppressedAttachState {
return SuppressedAttachState(
null,
- null,
- -1)
+ null)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
index 0b9bded5ef58..c7ac40346ce1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
@@ -29,7 +29,7 @@ import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -83,8 +83,8 @@ public class AppOpsCoordinator implements Coordinator {
}
- public NotifSection getSection() {
- return mNotifSection;
+ public NotifSectioner getSectioner() {
+ return mNotifSectioner;
}
/**
@@ -179,7 +179,7 @@ public class AppOpsCoordinator implements Coordinator {
/**
* Puts foreground service notifications into its own section.
*/
- private final NotifSection mNotifSection = new NotifSection("ForegroundService") {
+ private final NotifSectioner mNotifSectioner = new NotifSectioner("ForegroundService") {
@Override
public boolean isInSection(ListEntry entry) {
NotificationEntry notificationEntry = entry.getRepresentativeEntry();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
index c8e859f27a5c..dea11626a3f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
@@ -21,7 +21,7 @@ import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
import javax.inject.Inject
@@ -42,7 +42,7 @@ class ConversationCoordinator @Inject constructor(
}
}
- private val mNotifSection: NotifSection = object : NotifSection("People") {
+ val sectioner = object : NotifSectioner("People") {
override fun isInSection(entry: ListEntry): Boolean {
return isConversation(entry.representativeEntry!!)
}
@@ -52,10 +52,6 @@ class ConversationCoordinator @Inject constructor(
pipeline.addPromoter(notificationPromoter)
}
- fun getSection(): NotifSection {
- return mNotifSection
- }
-
private fun isConversation(entry: NotificationEntry): Boolean =
peopleNotificationIdentifier.getPeopleNotificationType(entry.sbn, entry.ranking) !=
TYPE_NON_PERSON
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
index 6e6cecaf62fa..c023400ca9ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
@@ -27,7 +27,7 @@ import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder;
@@ -88,8 +88,8 @@ public class HeadsUpCoordinator implements Coordinator {
pipeline.addNotificationLifetimeExtender(mLifetimeExtender);
}
- public NotifSection getSection() {
- return mNotifSection;
+ public NotifSectioner getSectioner() {
+ return mNotifSectioner;
}
private void onHeadsUpViewBound(NotificationEntry entry) {
@@ -191,7 +191,7 @@ public class HeadsUpCoordinator implements Coordinator {
}
};
- private final NotifSection mNotifSection = new NotifSection("HeadsUp") {
+ private final NotifSectioner mNotifSectioner = new NotifSectioner("HeadsUp") {
@Override
public boolean isInSection(ListEntry entry) {
return isCurrentlyShowingHun(entry);
@@ -207,7 +207,7 @@ public class HeadsUpCoordinator implements Coordinator {
endNotifLifetimeExtension();
mCurrentHun = newHUN;
mNotifPromoter.invalidateList();
- mNotifSection.invalidateList();
+ mNotifSectioner.invalidateList();
}
if (!isHeadsUp) {
mHeadsUpViewBinder.unbindHeadsUpView(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index 87ca717982f5..ded5e46593f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -21,7 +21,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
@@ -41,7 +41,7 @@ import javax.inject.Inject;
public class NotifCoordinators implements Dumpable {
private static final String TAG = "NotifCoordinators";
private final List<Coordinator> mCoordinators = new ArrayList<>();
- private final List<NotifSection> mOrderedSections = new ArrayList<>();
+ private final List<NotifSectioner> mOrderedSections = new ArrayList<>();
/**
* Creates all the coordinators.
@@ -81,12 +81,12 @@ public class NotifCoordinators implements Dumpable {
// Manually add Ordered Sections
// HeadsUp > FGS > People > Alerting > Silent > Unknown/Default
if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
- mOrderedSections.add(headsUpCoordinator.getSection()); // HeadsUp
+ mOrderedSections.add(headsUpCoordinator.getSectioner()); // HeadsUp
}
- mOrderedSections.add(appOpsCoordinator.getSection()); // ForegroundService
- mOrderedSections.add(conversationCoordinator.getSection()); // People
- mOrderedSections.add(rankingCoordinator.getAlertingSection()); // Alerting
- mOrderedSections.add(rankingCoordinator.getSilentSection()); // Silent
+ mOrderedSections.add(appOpsCoordinator.getSectioner()); // ForegroundService
+ mOrderedSections.add(conversationCoordinator.getSectioner()); // People
+ mOrderedSections.add(rankingCoordinator.getAlertingSectioner()); // Alerting
+ mOrderedSections.add(rankingCoordinator.getSilentSectioner()); // Silent
}
/**
@@ -109,7 +109,7 @@ public class NotifCoordinators implements Dumpable {
pw.println("\t" + c.getClass());
}
- for (NotifSection s : mOrderedSections) {
+ for (NotifSectioner s : mOrderedSections) {
pw.println("\t" + s.getName());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
index a32b1636057b..0f08e0ff491c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
@@ -22,7 +22,7 @@ import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import javax.inject.Inject;
@@ -57,22 +57,22 @@ public class RankingCoordinator implements Coordinator {
pipeline.addPreGroupFilter(mDozingFilter);
}
- public NotifSection getAlertingSection() {
- return mAlertingNotifSection;
+ public NotifSectioner getAlertingSectioner() {
+ return mAlertingNotifSectioner;
}
- public NotifSection getSilentSection() {
- return mSilentNotifSection;
+ public NotifSectioner getSilentSectioner() {
+ return mSilentNotifSectioner;
}
- private final NotifSection mAlertingNotifSection = new NotifSection("Alerting") {
+ private final NotifSectioner mAlertingNotifSectioner = new NotifSectioner("Alerting") {
@Override
public boolean isInSection(ListEntry entry) {
return mHighPriorityProvider.isHighPriority(entry);
}
};
- private final NotifSection mSilentNotifSection = new NotifSection("Silent") {
+ private final NotifSectioner mSilentNotifSectioner = new NotifSectioner("Silent") {
@Override
public boolean isInSection(ListEntry entry) {
return !mHighPriorityProvider.isHighPriority(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 7c061aad7b4a..e5425cfc8c93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -140,7 +140,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
.build();
ExpandableNotificationRowController rowController =
component.getExpandableNotificationRowController();
- rowController.init();
+ rowController.init(entry);
entry.setRowController(rowController);
bindRow(entry, row);
updateRow(entry, row);
@@ -160,7 +160,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
mNotificationRemoteInputManager.bindRow(row);
row.setOnActivatedListener(mPresenter);
entry.setRow(row);
- row.setEntry(entry);
mNotifBindPipeline.manageRow(entry, row);
mBindRowCallback.onBindRow(row);
}
diff --git a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
index f1ead3c8a441..c09122ea3c26 100644
--- a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
@@ -14,25 +14,14 @@
* limitations under the License.
*/
-package com.android.wm.shell;
+package com.android.systemui.statusbar.notification.collection.listbuilder
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for the shell.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class WindowManagerShellTest {
-
- WindowManagerShell mShell;
-
- @Test
- public void testNothing() {
- // Do nothing
- }
+data class NotifSection(
+ val sectioner: NotifSectioner,
+ val index: Int
+) {
+ val label: String
+ get() = "Section($index, \"${sectioner.name}\")"
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
index f7bfeb7234f0..9ee7db738c20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
@@ -25,7 +25,6 @@ import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection
import javax.inject.Inject
class ShadeListBuilderLogger @Inject constructor(
@@ -211,21 +210,17 @@ class ShadeListBuilderLogger @Inject constructor(
fun logSectionChanged(
buildId: Int,
prevSection: NotifSection?,
- prevIndex: Int,
- newSection: NotifSection?,
- newIndex: Int
+ newSection: NotifSection?
) {
buffer.log(TAG, INFO, {
long1 = buildId.toLong()
- str1 = prevSection?.name
- int1 = prevIndex
- str2 = newSection?.name
- int2 = newIndex
+ str1 = prevSection?.label
+ str2 = newSection?.label
}, {
if (str1 == null) {
- "(Build $long1) Section assigned: '$str2' (#$int2)"
+ "(Build $long1) Section assigned: $str2"
} else {
- "(Build $long1) Section changed: '$str1' (#$int1) -> '$str2' (#$int2)"
+ "(Build $long1) Section changed: $str1 -> $str2"
}
})
}
@@ -233,17 +228,14 @@ class ShadeListBuilderLogger @Inject constructor(
fun logSectionChangeSuppressed(
buildId: Int,
suppressedSection: NotifSection?,
- suppressedSectionIndex: Int,
assignedSection: NotifSection?
) {
buffer.log(TAG, INFO, {
long1 = buildId.toLong()
- str1 = suppressedSection?.name
- int1 = suppressedSectionIndex
- str2 = assignedSection?.name
+ str1 = suppressedSection?.label
+ str2 = assignedSection?.label
}, {
- "(Build $long1) Section change suppressed: '$str1' (#$int1). " +
- "Keeping section: '$str2'"
+ "(Build $long1) Suppressing section change to $str1 (staying at $str2)"
})
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
index fe5ba3c8e6fc..b57f504189f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
@@ -22,8 +22,8 @@ import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
/**
* Pluggable for participating in notif sectioning. See {@link ShadeListBuilder#setSections}.
*/
-public abstract class NotifSection extends Pluggable<NotifSection> {
- protected NotifSection(String name) {
+public abstract class NotifSectioner extends Pluggable<NotifSectioner> {
+ protected NotifSectioner(String name) {
super(name);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
index e8124944bcb0..a1800ed12125 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
@@ -25,10 +25,10 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain
* we should just modify NLC to implement the NodeController interface.
*/
class RootNodeController(
- private val listContainer: NotificationListContainer
+ private val listContainer: NotificationListContainer,
+ override val view: View
) : NodeController {
override val nodeLabel: String = "<root>"
- override val view: View = listContainer as View
override fun getChildAt(index: Int): View? {
return listContainer.getContainerChildAt(index)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
index 118ff4a9fbb7..3c35b7bd8472 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.collection.render
+import android.content.Context
+import android.view.View
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -30,12 +32,15 @@ import javax.inject.Inject
* currently populate the notification shade.
*/
class ShadeViewManager constructor(
+ context: Context,
listContainer: NotificationListContainer,
logger: ShadeViewDifferLogger,
private val viewBarn: NotifViewBarn,
private val notificationIconAreaController: NotificationIconAreaController
) {
- private val rootController = RootNodeController(listContainer)
+ // We pass a shim view here because the listContainer may not actually have a view associated
+ // with it and the differ never actually cares about the root node's view.
+ private val rootController = RootNodeController(listContainer, View(context))
private val viewDiffer = ShadeViewDiffer(rootController, logger)
fun attach(listBuilder: ShadeListBuilder) {
@@ -82,11 +87,17 @@ class ShadeViewManager constructor(
}
class ShadeViewManagerFactory @Inject constructor(
+ private val context: Context,
private val logger: ShadeViewDifferLogger,
private val viewBarn: NotifViewBarn,
private val notificationIconAreaController: NotificationIconAreaController
) {
fun create(listContainer: NotificationListContainer): ShadeViewManager {
- return ShadeViewManager(listContainer, logger, viewBarn, notificationIconAreaController)
+ return ShadeViewManager(
+ context,
+ listContainer,
+ logger,
+ viewBarn,
+ notificationIconAreaController)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 9c09cba5e137..46b497339d94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -141,7 +141,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
void onExpansionChanged(boolean isExpanded);
}
- private StatusBarStateController mStatusbarStateController;
+ private StatusBarStateController mStatusBarStateController;
private KeyguardBypassController mBypassController;
private LayoutListener mLayoutListener;
private RowContentBindStage mRowContentBindStage;
@@ -463,16 +463,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
/**
- * Set the entry for the row.
- *
- * @param entry the entry this row is tied to
- */
- public void setEntry(@NonNull NotificationEntry entry) {
- mEntry = entry;
- cacheIsSystemNotification();
- }
-
- /**
* Marks a content view as freeable, setting it so that future inflations do not reinflate
* and ensuring that the view is freed when it is safe to remove.
*
@@ -1584,6 +1574,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* Initialize row.
*/
public void initialize(
+ NotificationEntry entry,
String appName,
String notificationKey,
ExpansionLogger logger,
@@ -1598,6 +1589,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
StatusBarStateController statusBarStateController,
PeopleNotificationIdentifier peopleNotificationIdentifier,
OnUserInteractionCallback onUserInteractionCallback) {
+ mEntry = entry;
mAppName = appName;
if (mMenuRow == null) {
mMenuRow = new NotificationMenuRow(mContext, peopleNotificationIdentifier);
@@ -1616,12 +1608,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mMediaManager = notificationMediaManager;
setOnFeedbackClickListener(onFeedbackClickListener);
mFalsingManager = falsingManager;
- mStatusbarStateController = statusBarStateController;
+ mStatusBarStateController = statusBarStateController;
+
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
for (NotificationContentView l : mLayouts) {
l.setPeopleNotificationIdentifier(mPeopleNotificationIdentifier);
}
mOnUserInteractionCallback = onUserInteractionCallback;
+
+ cacheIsSystemNotification();
}
private void initDimens() {
@@ -2134,8 +2129,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
*/
@Override
public boolean isSoundEffectsEnabled() {
- final boolean mute = mStatusbarStateController != null
- && mStatusbarStateController.isDozing()
+ final boolean mute = mStatusBarStateController != null
+ && mStatusBarStateController.isDozing()
&& mSecureStateProvider != null &&
!mSecureStateProvider.getAsBoolean();
return !mute && super.isSoundEffectsEnabled();
@@ -2259,10 +2254,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
- /**
- * @param onKeyguard whether to prevent notification expansion
- */
- public void setOnKeyguard(boolean onKeyguard) {
+ void setOnKeyguard(boolean onKeyguard) {
if (onKeyguard != mOnKeyguard) {
boolean wasAboveShelf = isAboveShelf();
final boolean wasExpanded = isExpanded();
@@ -2331,7 +2323,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
private boolean isDozing() {
- return mStatusbarStateController != null && mStatusbarStateController.isDozing();
+ return mStatusBarStateController != null && mStatusBarStateController.isDozing();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index f8bc2bebf93b..ce760cb525f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.row;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import android.view.View;
import android.view.ViewGroup;
@@ -29,6 +30,7 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.render.NodeController;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
@@ -118,9 +120,10 @@ public class ExpandableNotificationRowController implements NodeController {
/**
* Initialize the controller.
*/
- public void init() {
+ public void init(NotificationEntry entry) {
mActivatableNotificationViewController.init();
mView.initialize(
+ entry,
mAppName,
mNotificationKey,
mExpansionLogger,
@@ -135,7 +138,15 @@ public class ExpandableNotificationRowController implements NodeController {
mStatusBarStateController,
mPeopleNotificationIdentifier,
mOnUserInteractionCallback
+
);
+ mStatusBarStateController.addCallback(new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ mView.setOnKeyguard(newState == KEYGUARD);
+ }
+ });
+ mView.setOnKeyguard(mStatusBarStateController.getState() == KEYGUARD);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
mView.setLongPressListener((v, x, y, item) -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 11e698b03823..d5e55315ff0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -42,7 +42,7 @@ public class AmbientState {
private static final float MAX_PULSE_HEIGHT = 100000f;
private final SectionProvider mSectionProvider;
- private ArrayList<ExpandableView> mDraggedViews = new ArrayList<>();
+ private ArrayList<View> mDraggedViews = new ArrayList<>();
private int mScrollY;
private int mAnchorViewIndex;
private int mAnchorViewY;
@@ -164,7 +164,7 @@ public class AmbientState {
}
/** Call when dragging begins. */
- public void onBeginDrag(ExpandableView view) {
+ public void onBeginDrag(View view) {
mDraggedViews.add(view);
}
@@ -172,7 +172,7 @@ public class AmbientState {
mDraggedViews.remove(view);
}
- public ArrayList<ExpandableView> getDraggedViews() {
+ public ArrayList<View> getDraggedViews() {
return mDraggedViews;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index d4c270f45ceb..b1a9efe40fdb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -44,7 +44,6 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.Paint;
-import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
@@ -54,7 +53,6 @@ import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -94,22 +92,13 @@ import com.android.systemui.Dumpable;
import com.android.systemui.ExpandHelper;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.SwipeHelper;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
@@ -145,7 +134,6 @@ import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -154,11 +142,8 @@ import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.ScrollAdapter;
-import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.Assert;
@@ -178,7 +163,7 @@ import javax.inject.Named;
/**
* A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
*/
-public class NotificationStackScrollLayout extends ViewGroup implements ScrollAdapter, Dumpable {
+public class NotificationStackScrollLayout extends ViewGroup implements Dumpable {
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
@@ -195,13 +180,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
* gap is drawn between them). In this case we don't want to round their corners.
*/
private static final int DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX = 1;
- private final KeyguardBypassController mKeyguardBypassController;
+ private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider;
private final DynamicPrivacyController mDynamicPrivacyController;
private final SysuiStatusBarStateController mStatusbarStateController;
- private final KeyguardMediaController mKeyguardMediaController;
private ExpandHelper mExpandHelper;
- private final NotificationSwipeHelper mSwipeHelper;
+ private NotificationSwipeHelper mSwipeHelper;
private int mCurrentStackHeight = Integer.MAX_VALUE;
private final Paint mBackgroundPaint = new Paint();
private final boolean mShouldDrawNotificationBackground;
@@ -249,11 +233,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private int mBottomMargin;
private int mBottomInset = 0;
private float mQsExpansionFraction;
+ private int mCurrentUserId;
/**
* The algorithm which calculates the properties for our children
*/
- protected final StackScrollAlgorithm mStackScrollAlgorithm;
+ private final StackScrollAlgorithm mStackScrollAlgorithm;
private final AmbientState mAmbientState;
private NotificationGroupManager mGroupManager;
@@ -326,7 +311,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
* motion.
*/
private int mMaxScrollAfterExpand;
- private ExpandableNotificationRow.LongPressListener mLongPressListener;
boolean mCheckForLeavebehind;
/**
@@ -348,12 +332,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
return true;
}
};
- private final UserChangedListener mLockscreenUserChangeListener = new UserChangedListener() {
- @Override
- public void onUserChanged(int userId) {
- updateSensitiveness(false /* animated */);
- }
- };
+
private StatusBar mStatusBar;
private int[] mTempInt2 = new int[2];
private boolean mGenerateChildOrderChangedEvent;
@@ -368,7 +347,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private boolean mForceNoOverlappingRendering;
private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>();
private FalsingManager mFalsingManager;
- private final ZenModeController mZenController;
private boolean mAnimationRunning;
private ViewTreeObserver.OnPreDrawListener mRunningAnimationUpdater
= new ViewTreeObserver.OnPreDrawListener() {
@@ -498,7 +476,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private ArrayList<BiConsumer<Float, Float>> mExpandedHeightListeners = new ArrayList<>();
private int mHeadsUpInset;
private HeadsUpAppearanceController mHeadsUpAppearanceController;
- private final NotificationLockscreenUserManager mLockscreenUserManager;
private final Rect mTmpRect = new Rect();
private final FeatureFlags mFeatureFlags;
private final NotifPipeline mNotifPipeline;
@@ -511,7 +488,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
protected final UiEventLogger mUiEventLogger;
private final NotificationRemoteInputManager mRemoteInputManager =
Dependency.get(NotificationRemoteInputManager.class);
- private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
private final DisplayMetrics mDisplayMetrics = Dependency.get(DisplayMetrics.class);
private final LockscreenGestureLogger mLockscreenGestureLogger =
@@ -536,11 +512,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private int mWaterfallTopInset;
private NotificationStackScrollLayoutController mController;
- private SysuiColorExtractor.OnColorsChangedListener mOnColorsChangedListener =
- (colorExtractor, which) -> {
- final boolean useDarkText = mColorExtractor.getNeutralColors().supportsDarkText();
- updateDecorViews(useDarkText);
- };
+ private boolean mKeyguardMediaControllorVisible;
private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener =
new ExpandableView.OnHeightChangedListener() {
@@ -555,20 +527,44 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
};
+ private final ScrollAdapter mScrollAdapter = new ScrollAdapter() {
+ @Override
+ public boolean isScrolledToTop() {
+ if (ANCHOR_SCROLLING) {
+ updateScrollAnchor();
+ // TODO: once we're recycling this will need to check the adapter position of the
+ // child
+ return mScrollAnchorView == getFirstChildNotGone() && mScrollAnchorViewY >= 0;
+ } else {
+ return mOwnScrollY == 0;
+ }
+ }
+
+ @Override
+ public boolean isScrolledToBottom() {
+ if (ANCHOR_SCROLLING) {
+ return getMaxPositiveScrollAmount() <= 0;
+ } else {
+ return mOwnScrollY >= getScrollRange();
+ }
+ }
+
+ @Override
+ public View getHostView() {
+ return NotificationStackScrollLayout.this;
+ }
+ };
+
@Inject
public NotificationStackScrollLayout(
@Named(VIEW_CONTEXT) Context context,
AttributeSet attrs,
NotificationRoundnessManager notificationRoundnessManager,
DynamicPrivacyController dynamicPrivacyController,
- SysuiStatusBarStateController statusBarStateController,
+ SysuiStatusBarStateController statusbarStateController,
HeadsUpManagerPhone headsUpManager,
- KeyguardBypassController keyguardBypassController,
- KeyguardMediaController keyguardMediaController,
FalsingManager falsingManager,
- NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationGutsManager notificationGutsManager,
- ZenModeController zenController,
NotificationSectionsManager notificationSectionsManager,
ForegroundServiceSectionController fgsSectionController,
ForegroundServiceDismissalFeatureController fgsFeatureController,
@@ -583,13 +579,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mRoundnessManager = notificationRoundnessManager;
- mLockscreenUserManager = notificationLockscreenUserManager;
mNotificationGutsManager = notificationGutsManager;
mHeadsUpManager = headsUpManager;
mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed);
- mKeyguardBypassController = keyguardBypassController;
mFalsingManager = falsingManager;
- mZenController = zenController;
mFgsSectionController = fgsSectionController;
mSectionsManager = notificationSectionsManager;
@@ -608,16 +601,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mExpandHelper = new ExpandHelper(getContext(), mExpandHelperCallback,
minHeight, maxHeight);
mExpandHelper.setEventSource(this);
- mExpandHelper.setScrollAdapter(this);
- mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, mNotificationCallback,
- getContext(), mMenuEventListener, mFalsingManager);
+ mExpandHelper.setScrollAdapter(mScrollAdapter);
+
mStackScrollAlgorithm = createStackScrollAlgorithm(context);
- initView(context);
mShouldDrawNotificationBackground =
res.getBoolean(R.bool.config_drawNotificationBackground);
- mFadeNotificationsOnDismiss =
- res.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
- mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
setOutlineProvider(mOutlineProvider);
// Blocking helper manager wants to know the expanded state, update as well.
@@ -667,20 +655,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
mDynamicPrivacyController = dynamicPrivacyController;
- mStatusbarStateController = statusBarStateController;
+ mStatusbarStateController = statusbarStateController;
initializeForegroundServiceSection(fgsFeatureController);
mUiEventLogger = uiEventLogger;
- mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
- mKeyguardMediaController = keyguardMediaController;
- keyguardMediaController.setVisibilityChangedListener((visible) -> {
- if (visible) {
- generateAddAnimation(keyguardMediaController.getView(), false /*fromMoreCard */);
- } else {
- generateRemoveAnimation(keyguardMediaController.getView());
- }
- requestChildrenUpdate();
- return null;
- });
}
private void initializeForegroundServiceSection(
@@ -719,7 +696,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
public float getWakeUpHeight() {
ExpandableView firstChild = getFirstChildWithBackground();
if (firstChild != null) {
- if (mKeyguardBypassController.getBypassEnabled()) {
+ if (mKeyguardBypassEnabledProvider.getBypassEnabled()) {
return firstChild.getHeadsUpHeightWithoutHeader();
} else {
return firstChild.getCollapsedHeight();
@@ -794,21 +771,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
};
}
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class))
- .addCallback(mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER);
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
- }
-
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationSwipeActionHelper getSwipeActionHelper() {
return mSwipeHelper;
@@ -898,7 +860,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
}
boolean shouldDrawBackground;
- if (mKeyguardBypassController.getBypassEnabled() && onKeyguard()) {
+ if (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()) {
shouldDrawBackground = isPulseExpanding();
} else {
shouldDrawBackground = !mAmbientState.isDozing() || anySectionHasVisibleChild;
@@ -1013,9 +975,18 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
}
+ private void reinitView() {
+ initView(getContext(), mKeyguardBypassEnabledProvider, mSwipeHelper);
+ }
+
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void initView(Context context) {
+ void initView(Context context,
+ KeyguardBypassEnabledProvider keyguardBypassEnabledProvider,
+ NotificationSwipeHelper swipeHelper) {
mScroller = new OverScroller(getContext());
+ mKeyguardBypassEnabledProvider = keyguardBypassEnabledProvider;
+ mSwipeHelper = swipeHelper;
+
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setClipChildren(false);
final ViewConfiguration configuration = ViewConfiguration.get(context);
@@ -1227,7 +1198,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
float end = start + child.getActualHeight();
boolean clip = clipStart > start && clipStart < end
|| clipEnd >= start && clipEnd <= end;
- clip &= !(first && isScrolledToTop());
+ clip &= !(first && mScrollAdapter.isScrolledToTop());
child.setDistanceToTopRoundness(clip ? Math.max(start - clipStart, 0)
: ExpandableView.NO_ROUNDNESS);
first = false;
@@ -1287,7 +1258,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private void requestChildrenUpdate() {
+ void requestChildrenUpdate() {
if (!mChildrenUpdateRequested) {
getViewTreeObserver().addOnPreDrawListener(mChildrenUpdater);
mChildrenUpdateRequested = true;
@@ -1417,7 +1388,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private void notifyAppearChangedListeners() {
float appear;
float expandAmount;
- if (mKeyguardBypassController.getBypassEnabled() && onKeyguard()) {
+ if (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()) {
appear = calculateAppearFractionBypass();
expandAmount = getPulseHeight();
} else {
@@ -1658,7 +1629,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
* @return the child at the given location.
*/
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
- private ExpandableView getChildAtPosition(float touchX, float touchY,
+ ExpandableView getChildAtPosition(float touchX, float touchY,
boolean requireMinHeight, boolean ignoreDecors) {
// find the view under the pointer, accounting for GONE views
final int count = getChildCount();
@@ -1806,7 +1777,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private boolean onKeyguard() {
+ boolean onKeyguard() {
return mStatusBarState == StatusBarState.KEYGUARD;
}
@@ -1819,7 +1790,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mSwipeHelper.setDensityScale(densityScale);
float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
- initView(getContext());
+ reinitView();
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -2220,7 +2191,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
springBack();
} else {
float overScrollTop = getCurrentOverScrollAmount(true /* top */);
- if (isScrolledToTop() && mScrollAnchorViewY > 0) {
+ if (mScrollAdapter.isScrolledToTop() && mScrollAnchorViewY > 0) {
notifyOverscrollTopListener(mScrollAnchorViewY,
isRubberbanded(true /* onTop */));
} else {
@@ -2268,7 +2239,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void springBack() {
if (ANCHOR_SCROLLING) {
- boolean overScrolledTop = isScrolledToTop() && mScrollAnchorViewY > 0;
+ boolean overScrolledTop = mScrollAdapter.isScrolledToTop() && mScrollAnchorViewY > 0;
int maxPositiveScrollAmount = getMaxPositiveScrollAmount();
boolean overscrolledBottom = maxPositiveScrollAmount < 0;
if (overScrolledTop || overscrolledBottom) {
@@ -2545,8 +2516,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateForwardAndBackwardScrollability() {
- boolean forwardScrollable = mScrollable && !isScrolledToBottom();
- boolean backwardsScrollable = mScrollable && !isScrolledToTop();
+ boolean forwardScrollable = mScrollable && !mScrollAdapter.isScrolledToBottom();
+ boolean backwardsScrollable = mScrollable && !mScrollAdapter.isScrolledToTop();
boolean changed = forwardScrollable != mForwardScrollable
|| backwardsScrollable != mBackwardScrollable;
mForwardScrollable = forwardScrollable;
@@ -2667,7 +2638,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
boolean shiftPulsingWithFirst = mHeadsUpManager.getAllEntries().count() <= 1
&& (mAmbientState.isDozing()
- || (mKeyguardBypassController.getBypassEnabled() && onKeyguard));
+ || (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard));
for (NotificationSection section : mSections) {
int minBottomPosition = minTopPosition;
if (section == lastSection) {
@@ -2830,7 +2801,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mLastScrollerY = 0;
// x velocity is set to 1 to avoid overscroller bug
mScroller.fling(0, 0, 1, velocityY, 0, 0, minY, maxY, 0,
- mExpandedInThisMotion && !isScrolledToTop() ? 0 : Integer.MAX_VALUE / 2);
+ mExpandedInThisMotion
+ && !mScrollAdapter.isScrolledToTop() ? 0 : Integer.MAX_VALUE / 2);
}
}
@@ -2937,7 +2909,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
} else {
mTopPaddingOverflow = 0;
}
- setTopPadding(topPadding, animate && !mKeyguardBypassController.getBypassEnabled());
+ setTopPadding(topPadding, animate && !mKeyguardBypassEnabledProvider.getBypassEnabled());
setExpandedHeight(mExpandedHeight);
}
@@ -3095,7 +3067,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
* @return Whether an animation was generated.
*/
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private boolean generateRemoveAnimation(ExpandableView child) {
+ boolean generateRemoveAnimation(ExpandableView child) {
if (removeRemovedChildFromHeadsUpChangeAnimations(child)) {
mAddedHeadsUpChildren.remove(child);
return false;
@@ -3332,7 +3304,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
- void onViewAddedInternal(ExpandableView child) {
+ private void onViewAddedInternal(ExpandableView child) {
updateHideSensitiveForChild(child);
child.setOnHeightChangedListener(mOnChildHeightChangedListener);
generateAddAnimation(child, false /* fromMoreCard */);
@@ -3343,7 +3315,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
if (ANCHOR_SCROLLING) {
// TODO: once we're recycling this will need to check the adapter position of the child
- if (child == getFirstChildNotGone() && (isScrolledToTop() || !mIsExpanded)) {
+ if (child == getFirstChildNotGone()
+ && (mScrollAdapter.isScrolledToTop() || !mIsExpanded)) {
// New child was added at the top while we're scrolled to the top;
// make it the new anchor view so that we stay at the top.
mScrollAnchorView = child;
@@ -3361,6 +3334,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
onViewRemovedInternal(row, childrenContainer);
}
+ public void notifyGroupChildAdded(ExpandableView row) {
+ onViewAddedInternal(row);
+ }
+
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setAnimationsEnabled(boolean animationsEnabled) {
mAnimationsEnabled = animationsEnabled;
@@ -3533,7 +3510,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
boolean performDisappearAnimation = !mIsExpanded
// Only animate if we still have pinned heads up, otherwise we just have the
// regular collapse animation of the lock screen
- || (mKeyguardBypassController.getBypassEnabled() && onKeyguard()
+ || (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()
&& mHeadsUpManager.hasPinnedHeadsUp());
if (performDisappearAnimation && !isHeadsUp) {
type = row.wasJustClicked()
@@ -3769,11 +3746,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
return y < getHeight() - getEmptyBottomMargin();
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void setLongPressListener(ExpandableNotificationRow.LongPressListener listener) {
- mLongPressListener = listener;
- }
-
private float getTouchSlop(MotionEvent event) {
// Adjust the touch slop if another gesture may be being performed.
return event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE
@@ -4227,7 +4199,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
case MotionEvent.ACTION_DOWN: {
final int y = (int) ev.getY();
- mScrolledToTopOnFirstDown = isScrolledToTop();
+ mScrolledToTopOnFirstDown = mScrollAdapter.isScrolledToTop();
final ExpandableView childAtTouchPos = getChildAtPosition(
ev.getX(), y, false /* requireMinHeight */, false /* ignoreDecors */);
if (childAtTouchPos == null) {
@@ -4386,7 +4358,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- private void setSwipingInProgress(boolean swiping) {
+ void setSwipingInProgress(boolean swiping) {
mSwipingInProgress = swiping;
if (swiping) {
requestDisallowInterceptTouchEvent(true);
@@ -4411,32 +4383,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
}
- @Override
- @ShadeViewRefactor(RefactorComponent.COORDINATOR)
- public boolean isScrolledToTop() {
- if (ANCHOR_SCROLLING) {
- updateScrollAnchor();
- // TODO: once we're recycling this will need to check the adapter position of the child
- return mScrollAnchorView == getFirstChildNotGone() && mScrollAnchorViewY >= 0;
- } else {
- return mOwnScrollY == 0;
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.COORDINATOR)
- public boolean isScrolledToBottom() {
- if (ANCHOR_SCROLLING) {
- return getMaxPositiveScrollAmount() <= 0;
- } else {
- return mOwnScrollY >= getScrollRange();
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public View getHostView() {
- return this;
+ boolean isScrolledToBottom() {
+ return mScrollAdapter.isScrolledToBottom();
}
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
@@ -4476,7 +4424,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mStatusBar.resetUserExpandedStates();
clearTemporaryViews();
clearUserLockedViews();
- ArrayList<ExpandableView> draggedViews = mAmbientState.getDraggedViews();
+ ArrayList<View> draggedViews = mAmbientState.getDraggedViews();
if (draggedViews.size() > 0) {
draggedViews.clear();
updateContinuousShadowDrawing();
@@ -4734,8 +4682,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void updateSensitiveness(boolean animate) {
- boolean hideSensitive = mLockscreenUserManager.isAnyProfilePublicMode();
+ void updateSensitiveness(boolean animate, boolean hideSensitive) {
if (hideSensitive != mAmbientState.isHideSensitive()) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -4927,7 +4874,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
// Since we are clipping to the outline we need to make sure that the shadows aren't
// clipped when pulsing
float ownTranslationZ = 0;
- if (mKeyguardBypassController.getBypassEnabled() && mAmbientState.isHiddenAtAll()) {
+ if (mKeyguardBypassEnabledProvider.getBypassEnabled() && mAmbientState.isHiddenAtAll()) {
ExpandableView firstChildNotGone = getFirstChildNotGone();
if (firstChildNotGone != null && firstChildNotGone.showingPulsing()) {
ownTranslationZ = firstChildNotGone.getTranslationZ();
@@ -4992,11 +4939,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void updateEmptyShadeView(boolean visible) {
+ void updateEmptyShadeView(boolean visible, boolean notifVisibleInShade) {
mEmptyShadeView.setVisible(visible, mIsExpanded && mAnimationsEnabled);
int oldTextRes = mEmptyShadeView.getTextResource();
- int newTextRes = mZenController.areNotificationsHiddenInShade()
+ int newTextRes = notifVisibleInShade
? R.string.dnd_suppressing_shade_text : R.string.empty_shade_text;
if (oldTextRes != newTextRes) {
mEmptyShadeView.setText(newTextRes);
@@ -5021,6 +4968,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
handleDismissAllClipping();
}
+ boolean getDismissAllInProgress() {
+ return mDismissAllInProgress;
+ }
+
@ShadeViewRefactor(RefactorComponent.ADAPTER)
private void handleDismissAllClipping() {
final int count = getChildCount();
@@ -5093,7 +5044,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private void requestAnimateEverything() {
+ void requestAnimateEverything() {
if (mIsExpanded && mAnimationsEnabled) {
mEverythingNeedsAnimation = true;
mNeedsAnimation = true;
@@ -5431,17 +5382,17 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mAmbientState.setStatusBarState(statusBarState);
}
- private void onStatePostChange() {
+ void onStatePostChange(boolean fromShadeLocked) {
boolean onKeyguard = onKeyguard();
+ mAmbientState.setActivatedChild(null);
+ mAmbientState.setDimmed(onKeyguard);
+
if (mHeadsUpAppearanceController != null) {
mHeadsUpAppearanceController.onStateChanged();
}
- SysuiStatusBarStateController state = (SysuiStatusBarStateController)
- Dependency.get(StatusBarStateController.class);
- updateSensitiveness(state.goingToFullShade() /* animate */);
- setDimmed(onKeyguard, state.fromShadeLocked() /* animate */);
+ setDimmed(onKeyguard, fromShadeLocked);
setExpandingEnabled(!onKeyguard);
ActivatableNotificationView activatedChild = getActivatedChild();
setActivatedChild(null);
@@ -5534,12 +5485,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
ExpandableView child = (ExpandableView) getTransientView(i);
child.dump(fd, pw, args);
}
- ArrayList<ExpandableView> draggedViews = mAmbientState.getDraggedViews();
+ ArrayList<View> draggedViews = mAmbientState.getDraggedViews();
int draggedCount = draggedViews.size();
pw.println(" Dragged Views: " + draggedCount);
for (int i = 0; i < draggedCount; i++) {
- ExpandableView child = (ExpandableView) draggedViews.get(i);
- child.dump(fd, pw, args);
+ View view = draggedViews.get(i);
+ if (view instanceof ExpandableView) {
+ ExpandableView expandableView = (ExpandableView) view;
+ expandableView.dump(fd, pw, args);
+ }
}
}
@@ -5771,7 +5725,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
*/
public float setPulseHeight(float height) {
mAmbientState.setPulseHeight(height);
- if (mKeyguardBypassController.getBypassEnabled()) {
+ if (mKeyguardBypassEnabledProvider.getBypassEnabled()) {
notifyAppearChangedListeners();
}
requestChildrenUpdate();
@@ -5792,6 +5746,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
requestChildrenUpdate();
}
+ public boolean isFullyAwake() {
+ return mAmbientState.isFullyAwake();
+ }
+
public void wakeUpFromPulse() {
setPulseHeight(getWakeUpHeight());
// Let's place the hidden views at the end of the pulsing notification to make sure we have
@@ -5849,6 +5807,39 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
return mController;
}
+ void setCurrentUserid(int userId) {
+ mCurrentUserId = userId;
+ }
+
+ void onMenuShown(View row) {
+ mSwipeHelper.onMenuShown(row);
+ }
+
+ void onMenuReset(View row) {
+ View translatingParentView = mSwipeHelper.getTranslatingParentView();
+ if (translatingParentView != null && row == translatingParentView) {
+ mSwipeHelper.clearExposedMenuView();
+ mSwipeHelper.clearTranslatingParentView();
+ if (row instanceof ExpandableNotificationRow) {
+ mHeadsUpManager.setMenuShown(
+ ((ExpandableNotificationRow) row).getEntry(), false);
+
+ }
+ }
+ }
+
+ void addSwipedOutView(View v) {
+ mSwipedOutViews.add(v);
+ }
+
+ void addDraggedView(View view) {
+ mAmbientState.onBeginDrag(view);
+ }
+
+ void removeDraggedView(View view) {
+ mAmbientState.onDragFinished(view);
+ }
+
/**
* A listener that is notified when the empty space below the notifications is clicked on
*/
@@ -5916,7 +5907,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mSectionsManager.updateSectionBoundaries(reason);
}
- private void updateContinuousBackgroundDrawing() {
+ void updateContinuousBackgroundDrawing() {
boolean continuousBackground = !mAmbientState.isFullyAwake()
&& !mAmbientState.getDraggedViews().isEmpty();
if (continuousBackground != mContinuousBackgroundUpdate) {
@@ -5930,7 +5921,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private void updateContinuousShadowDrawing() {
+ void updateContinuousShadowDrawing() {
boolean continuousShadowUpdate = mAnimationRunning
|| !mAmbientState.getDraggedViews().isEmpty();
if (continuousShadowUpdate != mContinuousShadowUpdate) {
@@ -5944,7 +5935,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void resetExposedMenuView(boolean animate, boolean force) {
+ void resetExposedMenuView(boolean animate, boolean force) {
mSwipeHelper.resetExposedMenuView(animate, force);
}
@@ -6204,277 +6195,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
}
- @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private final StateListener mStateListener = new StateListener() {
- @Override
- public void onStatePreChange(int oldState, int newState) {
- if (oldState == StatusBarState.SHADE_LOCKED && newState == StatusBarState.KEYGUARD) {
- requestAnimateEverything();
- }
- }
-
- @Override
- public void onStateChanged(int newState) {
- setStatusBarState(newState);
- }
-
- @Override
- public void onStatePostChange() {
- NotificationStackScrollLayout.this.onStatePostChange();
- }
- };
-
- @VisibleForTesting
- @ShadeViewRefactor(RefactorComponent.INPUT)
- protected final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() {
- @Override
- public void onMenuClicked(View view, int x, int y, MenuItem item) {
- if (mLongPressListener == null) {
- return;
- }
- if (view instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- mMetricsLogger.write(row.getEntry().getSbn().getLogMaker()
- .setCategory(MetricsEvent.ACTION_TOUCH_GEAR)
- .setType(MetricsEvent.TYPE_ACTION)
- );
- }
- mLongPressListener.onLongPress(view, x, y, item);
- }
-
- @Override
- public void onMenuReset(View row) {
- View translatingParentView = mSwipeHelper.getTranslatingParentView();
- if (translatingParentView != null && row == translatingParentView) {
- mSwipeHelper.clearExposedMenuView();
- mSwipeHelper.clearTranslatingParentView();
- if (row instanceof ExpandableNotificationRow) {
- mHeadsUpManager.setMenuShown(
- ((ExpandableNotificationRow) row).getEntry(), false);
-
- }
- }
- }
-
- @Override
- public void onMenuShown(View row) {
- if (row instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow notificationRow = (ExpandableNotificationRow) row;
- mMetricsLogger.write(notificationRow.getEntry().getSbn().getLogMaker()
- .setCategory(MetricsEvent.ACTION_REVEAL_GEAR)
- .setType(MetricsEvent.TYPE_ACTION));
- mHeadsUpManager.setMenuShown(notificationRow.getEntry(), true);
- mSwipeHelper.onMenuShown(row);
- mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
- false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
-
- // Check to see if we want to go directly to the notfication guts
- NotificationMenuRowPlugin provider = notificationRow.getProvider();
- if (provider.shouldShowGutsOnSnapOpen()) {
- MenuItem item = provider.menuItemToExposeOnSnap();
- if (item != null) {
- Point origin = provider.getRevealAnimationOrigin();
- mNotificationGutsManager.openGuts(row, origin.x, origin.y, item);
- } else {
- Log.e(TAG, "Provider has shouldShowGutsOnSnapOpen, but provided no "
- + "menu item in menuItemtoExposeOnSnap. Skipping.");
- }
-
- // Close the menu row since we went directly to the guts
- resetExposedMenuView(false, true);
- }
- }
- }
- };
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private final NotificationSwipeHelper.NotificationCallback mNotificationCallback =
- new NotificationSwipeHelper.NotificationCallback() {
- @Override
- public void onDismiss() {
- mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
- false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- }
-
- @Override
- public void onSnooze(StatusBarNotification sbn,
- NotificationSwipeActionHelper.SnoozeOption snoozeOption) {
- mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
- }
-
- @Override
- public void onSnooze(StatusBarNotification sbn, int hours) {
- mStatusBar.setNotificationSnoozed(sbn, hours);
- }
-
- @Override
- public boolean shouldDismissQuickly() {
- return NotificationStackScrollLayout.this.isExpanded() && mAmbientState.isFullyAwake();
- }
-
- @Override
- public void onDragCancelled(View v) {
- setSwipingInProgress(false);
- mFalsingManager.onNotificationStopDismissing();
- }
-
- /**
- * Handles cleanup after the given {@code view} has been fully swiped out (including
- * re-invoking dismiss logic in case the notification has not made its way out yet).
- */
- @Override
- public void onChildDismissed(View view) {
- if (!(view instanceof ActivatableNotificationView)) {
- return;
- }
- ActivatableNotificationView row = (ActivatableNotificationView) view;
- if (!row.isDismissed()) {
- handleChildViewDismissed(view);
- }
- ViewGroup transientContainer = row.getTransientContainer();
- if (transientContainer != null) {
- transientContainer.removeTransientView(view);
- }
- }
-
- /**
- * Starts up notification dismiss and tells the notification, if any, to remove itself from
- * layout.
- *
- * @param view view (e.g. notification) to dismiss from the layout
- */
-
- public void handleChildViewDismissed(View view) {
- setSwipingInProgress(false);
- if (mDismissAllInProgress) {
- return;
- }
-
- boolean isBlockingHelperShown = false;
-
- mAmbientState.onDragFinished(view);
- updateContinuousShadowDrawing();
-
- if (view instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- if (row.isHeadsUp()) {
- mHeadsUpManager.addSwipedOutNotification(
- row.getEntry().getSbn().getKey());
- }
- isBlockingHelperShown =
- row.performDismissWithBlockingHelper(false /* fromAccessibility */);
- }
-
- if (view instanceof PeopleHubView) {
- mSectionsManager.hidePeopleRow();
- }
-
- if (!isBlockingHelperShown) {
- mSwipedOutViews.add(view);
- }
- mFalsingManager.onNotificationDismissed();
- if (mFalsingManager.shouldEnforceBouncer()) {
- mStatusBar.executeRunnableDismissingKeyguard(
- null,
- null /* cancelAction */,
- false /* dismissShade */,
- true /* afterKeyguardGone */,
- false /* deferred */);
- }
- }
-
- @Override
- public boolean isAntiFalsingNeeded() {
- return onKeyguard();
- }
-
- @Override
- public View getChildAtPosition(MotionEvent ev) {
- View child = NotificationStackScrollLayout.this.getChildAtPosition(
- ev.getX(),
- ev.getY(),
- true /* requireMinHeight */,
- false /* ignoreDecors */);
- if (child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- ExpandableNotificationRow parent = row.getNotificationParent();
- if (parent != null && parent.areChildrenExpanded()
- && (parent.areGutsExposed()
- || mSwipeHelper.getExposedMenuView() == parent
- || (parent.getAttachedChildren().size() == 1
- && parent.getEntry().isClearable()))) {
- // In this case the group is expanded and showing the menu for the
- // group, further interaction should apply to the group, not any
- // child notifications so we use the parent of the child. We also do the same
- // if we only have a single child.
- child = parent;
- }
- }
- return child;
- }
-
- @Override
- public void onBeginDrag(View v) {
- mFalsingManager.onNotificationStartDismissing();
- setSwipingInProgress(true);
- mAmbientState.onBeginDrag((ExpandableView) v);
- updateContinuousShadowDrawing();
- updateContinuousBackgroundDrawing();
- requestChildrenUpdate();
- }
-
- @Override
- public void onChildSnappedBack(View animView, float targetLeft) {
- mAmbientState.onDragFinished(animView);
- updateContinuousShadowDrawing();
- updateContinuousBackgroundDrawing();
- if (animView instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) animView;
- if (row.isPinned() && !canChildBeDismissed(row)
- && row.getEntry().getSbn().getNotification().fullScreenIntent
- == null) {
- mHeadsUpManager.removeNotification(row.getEntry().getSbn().getKey(),
- true /* removeImmediately */);
- }
- }
- }
-
- @Override
- public boolean updateSwipeProgress(View animView, boolean dismissable,
- float swipeProgress) {
- // Returning true prevents alpha fading.
- return !mFadeNotificationsOnDismiss;
- }
-
- @Override
- public float getFalsingThresholdFactor() {
- return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
- }
-
- @Override
- public int getConstrainSwipeStartPosition() {
- NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
- if (menuRow != null) {
- return Math.abs(menuRow.getMenuSnapTarget());
- }
- return 0;
- }
-
- @Override
- public boolean canChildBeDismissed(View v) {
- return NotificationStackScrollLayout.canChildBeDismissed(v);
- }
-
- @Override
- public boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
- //TODO: b/131242807 for why this doesn't do anything with direction
- return canChildBeDismissed(v);
- }
- };
-
- private static boolean canChildBeDismissed(View v) {
+ static boolean canChildBeDismissed(View v) {
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
if (row.isBlockingHelperShowingAndTranslationFinished()) {
@@ -6517,7 +6238,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@SelectedRows int selectedRows) {
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
if (selectedRows == ROWS_ALL) {
- mNotifCollection.dismissAllNotifications(mLockscreenUserManager.getCurrentUserId());
+ mNotifCollection.dismissAllNotifications(mCurrentUserId);
} else {
final List<Pair<NotificationEntry, DismissedByUserStats>>
entriesWithRowsDismissedFromShade = new ArrayList<>();
@@ -6546,7 +6267,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
if (selectedRows == ROWS_ALL) {
try {
- mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId());
+ mBarService.onClearAllNotifications(mCurrentUserId);
} catch (Exception ex) {
}
}
@@ -6568,6 +6289,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
NotificationLogger.getNotificationLocation(entry)));
}
+ public void setKeyguardMediaControllorVisible(boolean keyguardMediaControllorVisible) {
+ mKeyguardMediaControllorVisible = keyguardMediaControllorVisible;
+ }
+
// ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
@ShadeViewRefactor(RefactorComponent.INPUT)
@@ -6576,8 +6301,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
/* Only ever called as a consequence of a lockscreen expansion gesture. */
@Override
public boolean onDraggedDown(View startingChild, int dragLengthY) {
- boolean canDragDown = hasActiveNotifications()
- || mKeyguardMediaController.getView().getVisibility() == VISIBLE;
+ boolean canDragDown = hasActiveNotifications() || mKeyguardMediaControllorVisible;
if (mStatusBarState == StatusBarState.KEYGUARD && canDragDown) {
mLockscreenGestureLogger.write(
MetricsEvent.ACTION_LS_SHADE,
@@ -6655,7 +6379,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@Override
public boolean isDragDownAnywhereEnabled() {
return mStatusbarStateController.getState() == StatusBarState.KEYGUARD
- && !mKeyguardBypassController.getBypassEnabled();
+ && !mKeyguardBypassEnabledProvider.getBypassEnabled();
}
};
@@ -6838,4 +6562,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
return INVALID;
}
}
+
+ interface KeyguardBypassEnabledProvider {
+ boolean getBypassEnabled();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 7c29ee2b5483..73b4cad4ced5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -18,18 +18,38 @@ package com.android.systemui.statusbar.notification.stack;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
+import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.PointF;
import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
import android.view.Display;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.widget.FrameLayout;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.SwipeHelper;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.media.KeyguardMediaController;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -42,6 +62,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -49,6 +70,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import java.util.function.BiConsumer;
@@ -56,11 +78,15 @@ import java.util.function.BiConsumer;
import javax.inject.Inject;
import javax.inject.Named;
+import kotlin.Unit;
+
/**
* Controller for {@link NotificationStackScrollLayout}.
*/
@StatusBarComponent.StatusBarScope
public class NotificationStackScrollLayoutController {
+ private static final String TAG = "StackScrollerController";
+
private final boolean mAllowLongPress;
private final NotificationGutsManager mNotificationGutsManager;
private final HeadsUpManagerPhone mHeadsUpManager;
@@ -68,9 +94,25 @@ public class NotificationStackScrollLayoutController {
private final TunerService mTunerService;
private final DynamicPrivacyController mDynamicPrivacyController;
private final ConfigurationController mConfigurationController;
+ private final ZenModeController mZenModeController;
+ private final MetricsLogger mMetricsLogger;
+ private final FalsingManager mFalsingManager;
+ private final NotificationSectionsManager mNotificationSectionsManager;
+ private final Resources mResources;
+ private final NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
+ private final KeyguardMediaController mKeyguardMediaController;
+ private final SysuiStatusBarStateController mStatusBarStateController;
+ private final KeyguardBypassController mKeyguardBypassController;
+ private final SysuiColorExtractor mColorExtractor;
+ private final NotificationLockscreenUserManager mLockscreenUserManager;
+ // TODO: StatusBar should be encapsulated behind a Controller
+ private final StatusBar mStatusBar;
+
+ private NotificationStackScrollLayout mView;
+ private boolean mFadeNotificationsOnDismiss;
+
private final NotificationListContainerImpl mNotificationListContainer =
new NotificationListContainerImpl();
- private NotificationStackScrollLayout mView;
@VisibleForTesting
final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
@@ -78,11 +120,14 @@ public class NotificationStackScrollLayoutController {
@Override
public void onViewAttachedToWindow(View v) {
mConfigurationController.addCallback(mConfigurationListener);
+ mStatusBarStateController.addCallback(
+ mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER);
}
@Override
public void onViewDetachedFromWindow(View v) {
mConfigurationController.removeCallback(mConfigurationListener);
+ mStatusBarStateController.removeCallback(mStateListener);
}
};
@@ -122,6 +167,279 @@ public class NotificationStackScrollLayoutController {
}
};
+ private final StatusBarStateController.StateListener mStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStatePreChange(int oldState, int newState) {
+ if (oldState == StatusBarState.SHADE_LOCKED
+ && newState == StatusBarState.KEYGUARD) {
+ mView.requestAnimateEverything();
+ }
+ }
+
+ @Override
+ public void onStateChanged(int newState) {
+ mView.setStatusBarState(newState);
+ }
+
+ @Override
+ public void onStatePostChange() {
+ mView.updateSensitiveness(mStatusBarStateController.goingToFullShade(),
+ mLockscreenUserManager.isAnyProfilePublicMode());
+ mView.onStatePostChange(mStatusBarStateController.fromShadeLocked());
+ }
+ };
+
+ private final UserChangedListener mLockscreenUserChangeListener = new UserChangedListener() {
+ @Override
+ public void onUserChanged(int userId) {
+ mView.setCurrentUserid(userId);
+ mView.updateSensitiveness(false, mLockscreenUserManager.isAnyProfilePublicMode());
+ }
+ };
+
+ private final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() {
+ @Override
+ public void onMenuClicked(
+ View view, int x, int y, NotificationMenuRowPlugin.MenuItem item) {
+ if (!mAllowLongPress) {
+ return;
+ }
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ mMetricsLogger.write(row.getEntry().getSbn().getLogMaker()
+ .setCategory(MetricsEvent.ACTION_TOUCH_GEAR)
+ .setType(MetricsEvent.TYPE_ACTION)
+ );
+ }
+ mNotificationGutsManager.openGuts(view, x, y, item);
+ }
+
+ @Override
+ public void onMenuReset(View row) {
+ mView.onMenuReset(row);
+ }
+
+ @Override
+ public void onMenuShown(View row) {
+ if (row instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow notificationRow = (ExpandableNotificationRow) row;
+ mMetricsLogger.write(notificationRow.getEntry().getSbn().getLogMaker()
+ .setCategory(MetricsEvent.ACTION_REVEAL_GEAR)
+ .setType(MetricsEvent.TYPE_ACTION));
+ mHeadsUpManager.setMenuShown(notificationRow.getEntry(), true);
+ mView.onMenuShown(row);
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+
+ // Check to see if we want to go directly to the notification guts
+ NotificationMenuRowPlugin provider = notificationRow.getProvider();
+ if (provider.shouldShowGutsOnSnapOpen()) {
+ NotificationMenuRowPlugin.MenuItem item = provider.menuItemToExposeOnSnap();
+ if (item != null) {
+ Point origin = provider.getRevealAnimationOrigin();
+ mNotificationGutsManager.openGuts(row, origin.x, origin.y, item);
+ } else {
+ Log.e(TAG, "Provider has shouldShowGutsOnSnapOpen, but provided no "
+ + "menu item in menuItemtoExposeOnSnap. Skipping.");
+ }
+
+ // Close the menu row since we went directly to the guts
+ mView.resetExposedMenuView(false, true);
+ }
+ }
+ }
+ };
+
+ private final NotificationSwipeHelper.NotificationCallback mNotificationCallback =
+ new NotificationSwipeHelper.NotificationCallback() {
+
+ @Override
+ public void onDismiss() {
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ }
+
+ @Override
+ public void onSnooze(StatusBarNotification sbn,
+ NotificationSwipeActionHelper.SnoozeOption snoozeOption) {
+ mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
+ }
+
+ @Override
+ public void onSnooze(StatusBarNotification sbn, int hours) {
+ mStatusBar.setNotificationSnoozed(sbn, hours);
+ }
+
+ @Override
+ public boolean shouldDismissQuickly() {
+ return mView.isExpanded() && mView.isFullyAwake();
+ }
+
+ @Override
+ public void onDragCancelled(View v) {
+ mView.setSwipingInProgress(false);
+ mFalsingManager.onNotificationStopDismissing();
+ }
+
+ /**
+ * Handles cleanup after the given {@code view} has been fully swiped out (including
+ * re-invoking dismiss logic in case the notification has not made its way out yet).
+ */
+ @Override
+ public void onChildDismissed(View view) {
+ if (!(view instanceof ActivatableNotificationView)) {
+ return;
+ }
+ ActivatableNotificationView row = (ActivatableNotificationView) view;
+ if (!row.isDismissed()) {
+ handleChildViewDismissed(view);
+ }
+ ViewGroup transientContainer = row.getTransientContainer();
+ if (transientContainer != null) {
+ transientContainer.removeTransientView(view);
+ }
+ }
+
+ /**
+ * Starts up notification dismiss and tells the notification, if any, to remove
+ * itself from the layout.
+ *
+ * @param view view (e.g. notification) to dismiss from the layout
+ */
+
+ public void handleChildViewDismissed(View view) {
+ mView.setSwipingInProgress(false);
+ if (mView.getDismissAllInProgress()) {
+ return;
+ }
+
+ boolean isBlockingHelperShown = false;
+
+ mView.removeDraggedView(view);
+ mView.updateContinuousShadowDrawing();
+
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ if (row.isHeadsUp()) {
+ mHeadsUpManager.addSwipedOutNotification(
+ row.getEntry().getSbn().getKey());
+ }
+ isBlockingHelperShown =
+ row.performDismissWithBlockingHelper(false /* fromAccessibility */);
+ }
+
+ if (view instanceof PeopleHubView) {
+ mNotificationSectionsManager.hidePeopleRow();
+ }
+
+ if (!isBlockingHelperShown) {
+ mView.addSwipedOutView(view);
+ }
+ mFalsingManager.onNotificationDismissed();
+ if (mFalsingManager.shouldEnforceBouncer()) {
+ mStatusBar.executeRunnableDismissingKeyguard(
+ null,
+ null /* cancelAction */,
+ false /* dismissShade */,
+ true /* afterKeyguardGone */,
+ false /* deferred */);
+ }
+ }
+
+ @Override
+ public boolean isAntiFalsingNeeded() {
+ return mView.onKeyguard();
+ }
+
+ @Override
+ public View getChildAtPosition(MotionEvent ev) {
+ View child = mView.getChildAtPosition(
+ ev.getX(),
+ ev.getY(),
+ true /* requireMinHeight */,
+ false /* ignoreDecors */);
+ if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ ExpandableNotificationRow parent = row.getNotificationParent();
+ if (parent != null && parent.areChildrenExpanded()
+ && (parent.areGutsExposed()
+ || mSwipeHelper.getExposedMenuView() == parent
+ || (parent.getAttachedChildren().size() == 1
+ && parent.getEntry().isClearable()))) {
+ // In this case the group is expanded and showing the menu for the
+ // group, further interaction should apply to the group, not any
+ // child notifications so we use the parent of the child. We also do the
+ // same if we only have a single child.
+ child = parent;
+ }
+ }
+ return child;
+ }
+
+ @Override
+ public void onBeginDrag(View v) {
+ mFalsingManager.onNotificationStartDismissing();
+ mView.setSwipingInProgress(true);
+ mView.addDraggedView(v);
+ mView.updateContinuousShadowDrawing();
+ mView.updateContinuousBackgroundDrawing();
+ mView.requestChildrenUpdate();
+ }
+
+ @Override
+ public void onChildSnappedBack(View animView, float targetLeft) {
+ mView.addDraggedView(animView);
+ mView.updateContinuousShadowDrawing();
+ mView.updateContinuousBackgroundDrawing();
+ if (animView instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) animView;
+ if (row.isPinned() && !canChildBeDismissed(row)
+ && row.getEntry().getSbn().getNotification().fullScreenIntent
+ == null) {
+ mHeadsUpManager.removeNotification(row.getEntry().getSbn().getKey(),
+ true /* removeImmediately */);
+ }
+ }
+ }
+
+ @Override
+ public boolean updateSwipeProgress(View animView, boolean dismissable,
+ float swipeProgress) {
+ // Returning true prevents alpha fading.
+ return !mFadeNotificationsOnDismiss;
+ }
+
+ @Override
+ public float getFalsingThresholdFactor() {
+ return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
+ }
+
+ @Override
+ public int getConstrainSwipeStartPosition() {
+ NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
+ if (menuRow != null) {
+ return Math.abs(menuRow.getMenuSnapTarget());
+ }
+ return 0;
+ }
+
+ @Override
+ public boolean canChildBeDismissed(View v) {
+ return NotificationStackScrollLayout.canChildBeDismissed(v);
+ }
+
+ @Override
+ public boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
+ //TODO: b/131242807 for why this doesn't do anything with direction
+ return canChildBeDismissed(v);
+ }
+ };
+
+ private NotificationSwipeHelper mSwipeHelper;
+
@Inject
public NotificationStackScrollLayoutController(
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
@@ -130,7 +448,19 @@ public class NotificationStackScrollLayoutController {
NotificationRoundnessManager notificationRoundnessManager,
TunerService tunerService,
DynamicPrivacyController dynamicPrivacyController,
- ConfigurationController configurationController) {
+ ConfigurationController configurationController,
+ SysuiStatusBarStateController statusBarStateController,
+ KeyguardMediaController keyguardMediaController,
+ KeyguardBypassController keyguardBypassController,
+ ZenModeController zenModeController,
+ SysuiColorExtractor colorExtractor,
+ NotificationLockscreenUserManager lockscreenUserManager,
+ MetricsLogger metricsLogger,
+ FalsingManager falsingManager,
+ NotificationSectionsManager notificationSectionsManager,
+ @Main Resources resources,
+ NotificationSwipeHelper.Builder notificationSwipeHelperBuilder,
+ StatusBar statusBar) {
mAllowLongPress = allowLongPress;
mNotificationGutsManager = notificationGutsManager;
mHeadsUpManager = headsUpManager;
@@ -138,19 +468,42 @@ public class NotificationStackScrollLayoutController {
mTunerService = tunerService;
mDynamicPrivacyController = dynamicPrivacyController;
mConfigurationController = configurationController;
+ mStatusBarStateController = statusBarStateController;
+ mKeyguardMediaController = keyguardMediaController;
+ mKeyguardBypassController = keyguardBypassController;
+ mZenModeController = zenModeController;
+ mColorExtractor = colorExtractor;
+ mLockscreenUserManager = lockscreenUserManager;
+ mMetricsLogger = metricsLogger;
+ mFalsingManager = falsingManager;
+ mNotificationSectionsManager = notificationSectionsManager;
+ mResources = resources;
+ mNotificationSwipeHelperBuilder = notificationSwipeHelperBuilder;
+ mStatusBar = statusBar;
}
public void attach(NotificationStackScrollLayout view) {
mView = view;
mView.setController(this);
- if (mAllowLongPress) {
- mView.setLongPressListener(mNotificationGutsManager::openGuts);
- }
+ mSwipeHelper = mNotificationSwipeHelperBuilder
+ .setSwipeDirection(SwipeHelper.X)
+ .setNotificationCallback(mNotificationCallback)
+ .setOnMenuEventListener(mMenuEventListener)
+ .build();
+
+ mView.initView(mView.getContext(), mKeyguardBypassController::getBypassEnabled,
+ mSwipeHelper);
mHeadsUpManager.addListener(mNotificationRoundnessManager); // TODO: why is this here?
mDynamicPrivacyController.addListener(mDynamicPrivacyControllerListener);
+ mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
+ mView.setCurrentUserid(mLockscreenUserManager.getCurrentUserId());
+
+ mFadeNotificationsOnDismiss = // TODO: this should probably be injected directly
+ mResources.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
+
mNotificationRoundnessManager.setOnRoundingChangedCallback(mView::invalidate);
mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded);
@@ -165,6 +518,23 @@ public class NotificationStackScrollLayoutController {
Settings.Secure.NOTIFICATION_DISMISS_RTL,
Settings.Secure.NOTIFICATION_HISTORY_ENABLED);
+ mColorExtractor.addOnColorsChangedListener((colorExtractor, which) -> {
+ final boolean useDarkText = mColorExtractor.getNeutralColors().supportsDarkText();
+ mView.updateDecorViews(useDarkText);
+ });
+
+ mKeyguardMediaController.setVisibilityChangedListener(visible -> {
+ mView.setKeyguardMediaControllorVisible(visible);
+ if (visible) {
+ mView.generateAddAnimation(
+ mKeyguardMediaController.getView(), false /*fromMoreCard */);
+ } else {
+ mView.generateRemoveAnimation(mKeyguardMediaController.getView());
+ }
+ mView.requestChildrenUpdate();
+ return Unit.INSTANCE;
+ });
+
if (mView.isAttachedToWindow()) {
mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
}
@@ -484,7 +854,7 @@ public class NotificationStackScrollLayoutController {
}
public void updateEmptyShadeView(boolean visible) {
- mView.updateEmptyShadeView(visible);
+ mView.updateEmptyShadeView(visible, mZenModeController.areNotificationsHiddenInShade());
}
public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
@@ -532,6 +902,13 @@ public class NotificationStackScrollLayoutController {
return mView.hasActiveClearableNotifications(selection);
}
+ /**
+ * Set the maximum number of notifications that can currently be displayed
+ */
+ public void setMaxDisplayedNotifications(int maxNotifications) {
+ mNotificationListContainer.setMaxDisplayedNotifications(maxNotifications);
+ }
+
public RemoteInputController.Delegate createDelegate() {
return mView.createDelegate();
}
@@ -646,7 +1023,7 @@ public class NotificationStackScrollLayoutController {
@Override
public void notifyGroupChildAdded(ExpandableView row) {
- mView.onViewAddedInternal(row);
+ mView.notifyGroupChildAdded(row);
}
@Override
@@ -712,7 +1089,7 @@ public class NotificationStackScrollLayoutController {
@Override
public NotificationSwipeActionHelper getSwipeActionHelper() {
- return mView.getSwipeActionHelper();
+ return mSwipeHelper;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index d3b8a8cd2093..1e80e88df1a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -19,15 +19,17 @@ package com.android.systemui.statusbar.notification.stack;
import android.animation.Animator;
import android.animation.ValueAnimator;
-import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Handler;
import android.service.notification.StatusBarNotification;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.SwipeHelper;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
@@ -36,6 +38,8 @@ import com.android.systemui.statusbar.notification.row.ExpandableView;
import java.lang.ref.WeakReference;
+import javax.inject.Inject;
+
class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeActionHelper {
@VisibleForTesting
@@ -58,10 +62,10 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
private boolean mPulsing;
NotificationSwipeHelper(
- int swipeDirection, NotificationCallback callback, Context context,
- NotificationMenuRowPlugin.OnMenuEventListener menuListener,
- FalsingManager falsingManager) {
- super(swipeDirection, callback, context, falsingManager);
+ Resources resources, ViewConfiguration viewConfiguration,
+ FalsingManager falsingManager, int swipeDirection, NotificationCallback callback,
+ NotificationMenuRowPlugin.OnMenuEventListener menuListener) {
+ super(swipeDirection, callback, resources, viewConfiguration, falsingManager);
mMenuListener = menuListener;
mCallback = callback;
mFalsingCheck = () -> resetExposedMenuView(true /* animate */, true /* force */);
@@ -74,7 +78,7 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
public void clearTranslatingParentView() { setTranslatingParentView(null); }
@VisibleForTesting
- protected void setTranslatingParentView(View view) { mTranslatingParentView = view; };
+ protected void setTranslatingParentView(View view) { mTranslatingParentView = view; }
public void setExposedMenuView(View view) {
mMenuExposedView = view;
@@ -90,7 +94,7 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
@VisibleForTesting
void setCurrentMenuRow(NotificationMenuRowPlugin menuRow) {
- mCurrMenuRowRef = menuRow != null ? new WeakReference(menuRow) : null;
+ mCurrMenuRowRef = menuRow != null ? new WeakReference<>(menuRow) : null;
}
public NotificationMenuRowPlugin getCurrentMenuRow() {
@@ -470,4 +474,42 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
void onDismiss();
}
+
+ static class Builder {
+ private final Resources mResources;
+ private final ViewConfiguration mViewConfiguration;
+ private final FalsingManager mFalsingManager;
+ private int mSwipeDirection;
+ private NotificationCallback mNotificationCallback;
+ private NotificationMenuRowPlugin.OnMenuEventListener mOnMenuEventListener;
+
+ @Inject
+ Builder(@Main Resources resources, ViewConfiguration viewConfiguration,
+ FalsingManager falsingManager) {
+ mResources = resources;
+ mViewConfiguration = viewConfiguration;
+ mFalsingManager = falsingManager;
+ }
+
+ Builder setSwipeDirection(int swipeDirection) {
+ mSwipeDirection = swipeDirection;
+ return this;
+ }
+
+ Builder setNotificationCallback(NotificationCallback notificationCallback) {
+ mNotificationCallback = notificationCallback;
+ return this;
+ }
+
+ Builder setOnMenuEventListener(
+ NotificationMenuRowPlugin.OnMenuEventListener onMenuEventListener) {
+ mOnMenuEventListener = onMenuEventListener;
+ return this;
+ }
+
+ NotificationSwipeHelper build() {
+ return new NotificationSwipeHelper(mResources, mViewConfiguration, mFalsingManager,
+ mSwipeDirection, mNotificationCallback, mOnMenuEventListener);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index a6811c6b8ba4..78fcd82dc1f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -45,6 +45,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.statusbar.NotificationMediaManager;
import libcore.io.IoUtils;
@@ -52,6 +53,7 @@ import libcore.io.IoUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Objects;
+import java.util.Optional;
import javax.inject.Inject;
@@ -68,6 +70,7 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
private final WallpaperManager mWallpaperManager;
private final KeyguardUpdateMonitor mUpdateMonitor;
private final Handler mH;
+ private final Optional<FaceAuthScreenBrightnessController> mFaceAuthScreenBrightnessController;
private boolean mCached;
private Bitmap mCache;
@@ -83,12 +86,14 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
KeyguardUpdateMonitor keyguardUpdateMonitor,
DumpManager dumpManager,
NotificationMediaManager mediaManager,
+ Optional<FaceAuthScreenBrightnessController> faceAuthScreenBrightnessController,
@Main Handler mainHandler) {
dumpManager.registerDumpable(getClass().getSimpleName(), this);
mWallpaperManager = wallpaperManager;
mCurrentUserId = ActivityManager.getCurrentUser();
mUpdateMonitor = keyguardUpdateMonitor;
mMediaManager = mediaManager;
+ mFaceAuthScreenBrightnessController = faceAuthScreenBrightnessController;
mH = mainHandler;
if (iWallpaperManager != null) {
@@ -128,6 +133,14 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
return LoaderResult.success(null);
}
+ Bitmap faceAuthWallpaper = null;
+ if (mFaceAuthScreenBrightnessController.isPresent()) {
+ faceAuthWallpaper = mFaceAuthScreenBrightnessController.get().getFaceAuthWallpaper();
+ if (faceAuthWallpaper != null) {
+ return LoaderResult.success(faceAuthWallpaper);
+ }
+ }
+
// Prefer the selected user (when specified) over the current user for the FLAG_SET_LOCK
// wallpaper.
final int lockWallpaperUserId =
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 5974a53fc86d..d83758a57401 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone;
import static android.view.View.GONE;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
@@ -31,6 +32,7 @@ import android.app.Fragment;
import android.app.StatusBarManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
@@ -70,6 +72,7 @@ import com.android.systemui.DejankUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.DisplayId;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
@@ -85,7 +88,6 @@ import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.RemoteInputController;
@@ -231,7 +233,7 @@ public class NotificationPanelViewController extends PanelViewController {
BiometricSourceType biometricSourceType) {
boolean
keyguardOrShadeLocked =
- mBarState == StatusBarState.KEYGUARD
+ mBarState == KEYGUARD
|| mBarState == StatusBarState.SHADE_LOCKED;
if (!running && mFirstBypassAttempt && keyguardOrShadeLocked && !mDozing
&& !mDelayShowingKeyguardStatusBar
@@ -259,6 +261,11 @@ public class NotificationPanelViewController extends PanelViewController {
private final MediaHierarchyManager mMediaHierarchyManager;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final Provider<KeyguardClockSwitchController> mKeyguardClockSwitchControllerProvider;
+ // Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
+ // If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
+ private final int mMaxKeyguardNotifications;
+ // Current max allowed keyguard notifications determined by measuring the panel
+ private int mMaxAllowedKeyguardNotifications;
private KeyguardAffordanceHelper mAffordanceHelper;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
@@ -482,6 +489,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Inject
public NotificationPanelViewController(NotificationPanelView view,
+ @Main Resources resources,
InjectionInflationController injectionInflationController,
NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler,
DynamicPrivacyController dynamicPrivacyController,
@@ -584,6 +592,7 @@ public class NotificationPanelViewController extends PanelViewController {
mView.getOverlay().add(new DebugDrawable());
}
+ mMaxKeyguardNotifications = resources.getInteger(R.integer.keyguard_max_notification_count);
onFinishInflate();
}
@@ -761,6 +770,20 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete);
}
+ private void updateMaxDisplayedNotifications(boolean recompute) {
+ if (recompute) {
+ mMaxAllowedKeyguardNotifications = Math.max(computeMaxKeyguardNotifications(), 1);
+ }
+
+ if (mKeyguardShowing && !mKeyguardBypassController.getBypassEnabled()) {
+ mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(
+ mMaxAllowedKeyguardNotifications);
+ } else {
+ // no max when not on the keyguard
+ mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(-1);
+ }
+ }
+
public void setKeyguardIndicationController(KeyguardIndicationController indicationController) {
mKeyguardIndicationController = indicationController;
mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea);
@@ -821,7 +844,7 @@ public class NotificationPanelViewController extends PanelViewController {
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
boolean animateClock = animate || mAnimateNextPositionUpdate;
int stackScrollerPadding;
- if (mBarState != StatusBarState.KEYGUARD) {
+ if (mBarState != KEYGUARD) {
stackScrollerPadding = getUnlockedStackScrollerPadding();
} else {
int totalHeight = mView.getHeight();
@@ -865,20 +888,17 @@ public class NotificationPanelViewController extends PanelViewController {
}
/**
- * @param maximum the maximum to return at most
* @return the maximum keyguard notifications that can fit on the screen
*/
- public int computeMaxKeyguardNotifications(int maximum) {
+ private int computeMaxKeyguardNotifications() {
float minPadding = mClockPositionAlgorithm.getMinStackScrollerPadding();
int notificationPadding = Math.max(
1, mResources.getDimensionPixelSize(R.dimen.notification_divider_height));
- NotificationShelf shelf = mNotificationShelfController.getView();
- float
- shelfSize =
- shelf.getVisibility() == View.GONE ? 0
- : shelf.getIntrinsicHeight() + notificationPadding;
- float
- availableSpace =
+ float shelfSize =
+ mNotificationShelfController.getVisibility() == View.GONE
+ ? 0
+ : mNotificationShelfController.getIntrinsicHeight() + notificationPadding;
+ float availableSpace =
mNotificationStackScrollLayoutController.getHeight() - minPadding - shelfSize
- Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding)
- mKeyguardStatusView.getLogoutButtonHeight();
@@ -908,7 +928,8 @@ public class NotificationPanelViewController extends PanelViewController {
availableSpace -= mNotificationStackScrollLayoutController
.calculateGapHeight(previousView, child, count);
previousView = child;
- if (availableSpace >= 0 && count < maximum) {
+ if (availableSpace >= 0
+ && (mMaxKeyguardNotifications == -1 || count < mMaxKeyguardNotifications)) {
count++;
} else if (availableSpace > -shelfSize) {
// if we are exactly the last view, then we can show us still!
@@ -1235,7 +1256,7 @@ public class NotificationPanelViewController extends PanelViewController {
float vel = getCurrentQSVelocity();
final int
gesture =
- mBarState == StatusBarState.KEYGUARD ? MetricsEvent.ACTION_LS_QS
+ mBarState == KEYGUARD ? MetricsEvent.ACTION_LS_QS
: MetricsEvent.ACTION_SHADE_QS_PULL;
mLockscreenGestureLogger.write(gesture,
(int) ((y - mInitialTouchY) / mStatusBar.getDisplayDensity()),
@@ -1292,7 +1313,7 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean handleQsTouch(MotionEvent event) {
final int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
- && mBarState != StatusBarState.KEYGUARD && !mQsExpanded && mQsExpansionEnabled) {
+ && mBarState != KEYGUARD && !mQsExpanded && mQsExpansionEnabled) {
// Down in the empty area while fully expanded - go to QS.
mQsTracking = true;
@@ -1646,7 +1667,7 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardStateController.getShortenedFadingAwayDuration()).setInterpolator(
Interpolators.ALPHA_OUT).withEndAction(
mAnimateKeyguardBottomAreaInvisibleEndRunnable).start();
- } else if (statusBarState == StatusBarState.KEYGUARD
+ } else if (statusBarState == KEYGUARD
|| statusBarState == StatusBarState.SHADE_LOCKED) {
mKeyguardBottomArea.setVisibility(View.VISIBLE);
mKeyguardBottomArea.setAlpha(1f);
@@ -1659,8 +1680,8 @@ public class NotificationPanelViewController extends PanelViewController {
boolean goingToFullShade) {
mKeyguardStatusView.animate().cancel();
mKeyguardStatusViewAnimating = false;
- if ((!keyguardFadingAway && mBarState == StatusBarState.KEYGUARD
- && statusBarState != StatusBarState.KEYGUARD) || goingToFullShade) {
+ if ((!keyguardFadingAway && mBarState == KEYGUARD
+ && statusBarState != KEYGUARD) || goingToFullShade) {
mKeyguardStatusViewAnimating = true;
mKeyguardStatusView.animate().alpha(0f).setStartDelay(0).setDuration(
160).setInterpolator(Interpolators.ALPHA_OUT).withEndAction(
@@ -1671,14 +1692,14 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardStateController.getShortenedFadingAwayDuration()).start();
}
} else if (mBarState == StatusBarState.SHADE_LOCKED
- && statusBarState == StatusBarState.KEYGUARD) {
+ && statusBarState == KEYGUARD) {
mKeyguardStatusView.setVisibility(View.VISIBLE);
mKeyguardStatusViewAnimating = true;
mKeyguardStatusView.setAlpha(0f);
mKeyguardStatusView.animate().alpha(1f).setStartDelay(0).setDuration(
320).setInterpolator(Interpolators.ALPHA_IN).withEndAction(
mAnimateKeyguardStatusViewVisibleEndRunnable);
- } else if (statusBarState == StatusBarState.KEYGUARD) {
+ } else if (statusBarState == KEYGUARD) {
if (keyguardFadingAway) {
mKeyguardStatusViewAnimating = true;
mKeyguardStatusView.animate().alpha(0).translationYBy(
@@ -1698,7 +1719,7 @@ public class NotificationPanelViewController extends PanelViewController {
private void updateQsState() {
mNotificationStackScrollLayoutController.setQsExpanded(mQsExpanded);
mNotificationStackScrollLayoutController.setScrollingEnabled(
- mBarState != StatusBarState.KEYGUARD && (!mQsExpanded
+ mBarState != KEYGUARD && (!mQsExpanded
|| mQsExpansionFromOverscroll));
updateEmptyShadeView();
@@ -1725,7 +1746,7 @@ public class NotificationPanelViewController extends PanelViewController {
updateQsExpansion();
requestScrollerTopPaddingUpdate(false /* animate */);
updateHeaderKeyguardAlpha();
- if (mBarState == StatusBarState.SHADE_LOCKED || mBarState == StatusBarState.KEYGUARD) {
+ if (mBarState == StatusBarState.SHADE_LOCKED || mBarState == KEYGUARD) {
updateKeyguardBottomAreaAlpha();
updateBigClockAlpha();
}
@@ -1767,7 +1788,7 @@ public class NotificationPanelViewController extends PanelViewController {
// Upon initialisation when we are not layouted yet we don't want to announce that we
// are fully expanded, hence the != 0.0f check.
return mResources.getString(R.string.accessibility_desc_quick_settings);
- } else if (mBarState == StatusBarState.KEYGUARD) {
+ } else if (mBarState == KEYGUARD) {
return mResources.getString(R.string.accessibility_desc_lock_screen);
} else {
return mResources.getString(R.string.accessibility_desc_notification_shade);
@@ -1785,7 +1806,7 @@ public class NotificationPanelViewController extends PanelViewController {
// for a nice motion.
int maxNotificationPadding = getKeyguardNotificationStaticPadding();
int maxQsPadding = mQsMaxExpansionHeight + mQsNotificationTopPadding;
- int max = mBarState == StatusBarState.KEYGUARD ? Math.max(
+ int max = mBarState == KEYGUARD ? Math.max(
maxNotificationPadding, maxQsPadding) : maxQsPadding;
return (int) MathUtils.lerp((float) mQsMinExpansionHeight, (float) max,
getExpandedFraction());
@@ -1973,7 +1994,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected boolean canCollapsePanelOnTouch() {
if (!isInSettings()) {
- return mBarState == StatusBarState.KEYGUARD
+ return mBarState == KEYGUARD
|| mIsPanelCollapseOnQQS
|| mNotificationStackScrollLayoutController.isScrolledToBottom();
} else {
@@ -1983,7 +2004,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected int getMaxPanelHeight() {
- if (mKeyguardBypassController.getBypassEnabled() && mBarState == StatusBarState.KEYGUARD) {
+ if (mKeyguardBypassController.getBypassEnabled() && mBarState == KEYGUARD) {
return getMaxPanelHeightBypass();
} else {
return getMaxPanelHeightNonBypass();
@@ -1992,7 +2013,7 @@ public class NotificationPanelViewController extends PanelViewController {
private int getMaxPanelHeightNonBypass() {
int min = mStatusBarMinHeight;
- if (!(mBarState == StatusBarState.KEYGUARD)
+ if (!(mBarState == KEYGUARD)
&& mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0) {
int minHeight = (int) (mQsMinExpansionHeight + getOverExpansionAmount());
min = Math.max(min, minHeight);
@@ -2095,7 +2116,7 @@ public class NotificationPanelViewController extends PanelViewController {
int maxHeight = mNotificationStackScrollLayoutController.getHeight() - emptyBottomMargin;
maxHeight += mNotificationStackScrollLayoutController.getTopPaddingOverflow();
- if (mBarState == StatusBarState.KEYGUARD) {
+ if (mBarState == KEYGUARD) {
int
minKeyguardPanelBottom =
mClockPositionAlgorithm.getExpandedClockPosition()
@@ -2132,7 +2153,7 @@ public class NotificationPanelViewController extends PanelViewController {
maxQsHeight = (int) mQsSizeChangeAnimator.getAnimatedValue();
}
float totalHeight = Math.max(maxQsHeight,
- mBarState == StatusBarState.KEYGUARD ? mClockPositionResult.stackScrollerPadding
+ mBarState == KEYGUARD ? mClockPositionResult.stackScrollerPadding
: 0) + notificationHeight
+ mNotificationStackScrollLayoutController.getTopPaddingOverflow();
if (totalHeight > mNotificationStackScrollLayoutController.getHeight()) {
@@ -2151,7 +2172,7 @@ public class NotificationPanelViewController extends PanelViewController {
&& !mHeadsUpManager.hasPinnedHeadsUp()) {
alpha = getFadeoutAlpha();
}
- if (mBarState == StatusBarState.KEYGUARD && !mHintAnimationRunning
+ if (mBarState == KEYGUARD && !mHintAnimationRunning
&& !mKeyguardBypassController.getBypassEnabled()) {
alpha *= mClockPositionResult.clockAlpha;
}
@@ -2190,14 +2211,14 @@ public class NotificationPanelViewController extends PanelViewController {
* Hides the header when notifications are colliding with it.
*/
private void updateHeader() {
- if (mBarState == StatusBarState.KEYGUARD) {
+ if (mBarState == KEYGUARD) {
updateHeaderKeyguardAlpha();
}
updateQsExpansion();
}
protected float getHeaderTranslation() {
- if (mBarState == StatusBarState.KEYGUARD && !mKeyguardBypassController.getBypassEnabled()) {
+ if (mBarState == KEYGUARD && !mKeyguardBypassController.getBypassEnabled()) {
return -mQs.getQsMinExpansionHeight();
}
float appearAmount = mNotificationStackScrollLayoutController
@@ -2227,7 +2248,7 @@ public class NotificationPanelViewController extends PanelViewController {
*/
private float getKeyguardContentsAlpha() {
float alpha;
- if (mBarState == StatusBarState.KEYGUARD) {
+ if (mBarState == KEYGUARD) {
// When on Keyguard, we hide the header as soon as we expanded close enough to the
// header
@@ -2376,7 +2397,7 @@ public class NotificationPanelViewController extends PanelViewController {
if (mConflictingQsExpansionGesture || mQsExpandImmediate) {
return;
}
- if (mBarState != StatusBarState.KEYGUARD) {
+ if (mBarState != KEYGUARD) {
mNotificationStackScrollLayoutController.setOnHeightChangedListener(null);
if (isPixels) {
mNotificationStackScrollLayoutController.setOverScrolledPixels(
@@ -2398,7 +2419,7 @@ public class NotificationPanelViewController extends PanelViewController {
mQsExpandImmediate = true;
mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true);
}
- if (mBarState == StatusBarState.KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) {
+ if (mBarState == KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) {
mAffordanceHelper.animateHideLeftRightIcon();
}
mNotificationStackScrollLayoutController.onPanelTrackingStarted();
@@ -2413,7 +2434,7 @@ public class NotificationPanelViewController extends PanelViewController {
true /* animate */);
}
mNotificationStackScrollLayoutController.onPanelTrackingStopped();
- if (expand && (mBarState == StatusBarState.KEYGUARD
+ if (expand && (mBarState == KEYGUARD
|| mBarState == StatusBarState.SHADE_LOCKED)) {
if (!mHintAnimationRunning) {
mAffordanceHelper.reset(true);
@@ -2564,7 +2585,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected boolean onMiddleClicked() {
switch (mBarState) {
- case StatusBarState.KEYGUARD:
+ case KEYGUARD:
if (!mDozingOnDown) {
if (mKeyguardBypassController.getBypassEnabled()) {
mUpdateMonitor.requestFaceAuth();
@@ -2579,7 +2600,7 @@ public class NotificationPanelViewController extends PanelViewController {
return true;
case StatusBarState.SHADE_LOCKED:
if (!mQsExpanded) {
- mStatusBarStateController.setState(StatusBarState.KEYGUARD);
+ mStatusBarStateController.setState(KEYGUARD);
}
return true;
case StatusBarState.SHADE:
@@ -2750,7 +2771,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
private boolean isOnKeyguard() {
- return mBarState == StatusBarState.KEYGUARD;
+ return mBarState == KEYGUARD;
}
public void setPanelScrimMinFraction(float minFraction) {
@@ -2925,7 +2946,7 @@ public class NotificationPanelViewController extends PanelViewController {
mBottomAreaShadeAlphaAnimator.cancel();
}
- if (mBarState == StatusBarState.KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) {
+ if (mBarState == KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) {
updateDozingVisibilities(animate);
}
@@ -2953,7 +2974,7 @@ public class NotificationPanelViewController extends PanelViewController {
public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) {
if (mAmbientIndicationBottomPadding != ambientIndicationBottomPadding) {
mAmbientIndicationBottomPadding = ambientIndicationBottomPadding;
- mStatusBar.updateKeyguardMaxNotifications();
+ updateMaxDisplayedNotifications(true);
}
}
@@ -3057,7 +3078,7 @@ public class NotificationPanelViewController extends PanelViewController {
private void updateShowEmptyShadeView() {
boolean
showEmptyShadeView =
- mBarState != StatusBarState.KEYGUARD && !mEntryManager.hasActiveNotifications();
+ mBarState != KEYGUARD && !mEntryManager.hasActiveNotifications();
showEmptyShadeView(showEmptyShadeView);
}
@@ -3127,6 +3148,7 @@ public class NotificationPanelViewController extends PanelViewController {
mNotificationStackScrollLayoutController.setScrimController(scrimController);
updateShowEmptyShadeView();
mNotificationShelfController = notificationShelfController;
+ updateMaxDisplayedNotifications(true);
}
public void showTransientIndication(int id) {
@@ -3506,7 +3528,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
public boolean needsAntiFalsing() {
- return mBarState == StatusBarState.KEYGUARD;
+ return mBarState == KEYGUARD;
}
}
@@ -3619,14 +3641,15 @@ public class NotificationPanelViewController extends PanelViewController {
boolean goingToFullShade = mStatusBarStateController.goingToFullShade();
boolean keyguardFadingAway = mKeyguardStateController.isKeyguardFadingAway();
int oldState = mBarState;
- boolean keyguardShowing = statusBarState == StatusBarState.KEYGUARD;
+ boolean keyguardShowing = statusBarState == KEYGUARD;
+
setKeyguardStatusViewVisibility(statusBarState, keyguardFadingAway, goingToFullShade);
setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
mBarState = statusBarState;
mKeyguardShowing = keyguardShowing;
- if (oldState == StatusBarState.KEYGUARD && (goingToFullShade
+ if (oldState == KEYGUARD && (goingToFullShade
|| statusBarState == StatusBarState.SHADE_LOCKED)) {
animateKeyguardStatusBarOut();
long
@@ -3635,7 +3658,7 @@ public class NotificationPanelViewController extends PanelViewController {
: mKeyguardStateController.calculateGoingToFullShadeDelay();
mQs.animateHeaderSlidingIn(delay);
} else if (oldState == StatusBarState.SHADE_LOCKED
- && statusBarState == StatusBarState.KEYGUARD) {
+ && statusBarState == KEYGUARD) {
animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
mNotificationStackScrollLayoutController.resetScrollPosition();
// Only animate header if the header is visible. If not, it will partially
@@ -3657,7 +3680,9 @@ public class NotificationPanelViewController extends PanelViewController {
if (keyguardShowing) {
updateDozingVisibilities(false /* animate */);
}
- // THe update needs to happen after the headerSlide in above, otherwise the translation
+
+ updateMaxDisplayedNotifications(false);
+ // The update needs to happen after the headerSlide in above, otherwise the translation
// would reset
updateQSPulseExpansion();
maybeAnimateBottomAreaAlpha();
@@ -3713,6 +3738,7 @@ public class NotificationPanelViewController extends PanelViewController {
int oldTop, int oldRight, int oldBottom) {
DejankUtils.startDetectingBlockingIpcs("NVP#onLayout");
super.onLayoutChange(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom);
+ updateMaxDisplayedNotifications(true);
setIsFullWidth(mNotificationStackScrollLayoutController.getWidth() == mView.getWidth());
// Update Clock Pivot
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 3c43a1777171..9ea402d4e6df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -101,6 +101,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
mCallbacks = Lists.newArrayList();
private final SysuiColorExtractor mColorExtractor;
+ private float mFaceAuthDisplayBrightness = LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
@Inject
public NotificationShadeWindowControllerImpl(Context context, WindowManager windowManager,
@@ -232,6 +233,12 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
mScreenBrightnessDoze = value / 255f;
}
+ @Override
+ public void setFaceAuthDisplayBrightness(float brightness) {
+ mFaceAuthDisplayBrightness = brightness;
+ apply(mCurrentState);
+ }
+
private void setKeyguardDark(boolean dark) {
int vis = mNotificationShadeView.getSystemUiVisibility();
if (dark) {
@@ -436,7 +443,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
if (state.mForceDozeBrightness) {
mLpChanged.screenBrightness = mScreenBrightnessDoze;
} else {
- mLpChanged.screenBrightness = LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
+ mLpChanged.screenBrightness = mFaceAuthDisplayBrightness;
}
}
@@ -645,6 +652,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
pw.println(TAG + ":");
pw.println(" mKeyguardDisplayMode=" + mKeyguardDisplayMode);
pw.println(mCurrentState);
+ mNotificationShadeView.getViewRootImpl().dump(" ", fd, pw, args);
}
@Override
@@ -701,6 +709,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
boolean mHeadsUpShowing;
boolean mForceCollapsed;
boolean mForceDozeBrightness;
+ int mFaceAuthDisplayBrightness;
boolean mForceUserActivity;
boolean mLaunchingActivity;
boolean mBackdropShowing;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index ac329e2598a9..965368e78e69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -1325,7 +1325,6 @@ public abstract class PanelViewController {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
- mStatusBar.onPanelLaidOut();
requestPanelHeightUpdate();
mHasLayoutedSinceDown = true;
if (mUpdateFlingOnLayout) {
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 6e37f90f9d94..115d164bd761 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -177,7 +177,7 @@ import com.android.systemui.recents.Recents;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CommandQueue;
@@ -388,7 +388,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
private final Provider<StatusBarComponent.Builder> mStatusBarComponentBuilder;
private final PluginManager mPluginManager;
- private final Optional<Divider> mDividerOptional;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private final StatusBarNotificationActivityStarter.Builder
mStatusBarNotificationActivityStarterBuilder;
private final ShadeController mShadeController;
@@ -721,7 +721,7 @@ public class StatusBar extends SystemUI implements DemoMode,
Optional<Recents> recentsOptional,
Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
- Optional<Divider> dividerOptional,
+ Optional<SplitScreen> splitScreenOptional,
LightsOutNotifController lightsOutNotifController,
StatusBarNotificationActivityStarter.Builder
statusBarNotificationActivityStarterBuilder,
@@ -803,7 +803,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mRecentsOptional = recentsOptional;
mStatusBarComponentBuilder = statusBarComponentBuilder;
mPluginManager = pluginManager;
- mDividerOptional = dividerOptional;
+ mSplitScreenOptional = splitScreenOptional;
mStatusBarNotificationActivityStarterBuilder = statusBarNotificationActivityStarterBuilder;
mShadeController = shadeController;
mSuperStatusBarViewFactory = superStatusBarViewFactory;
@@ -1550,31 +1550,32 @@ public class StatusBar extends SystemUI implements DemoMode,
if (!mRecentsOptional.isPresent()) {
return false;
}
- Divider divider = null;
- if (mDividerOptional.isPresent()) {
- divider = mDividerOptional.get();
- }
- if (divider == null || !divider.isDividerVisible()) {
- final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition(mDisplayId);
- if (navbarPos == NAV_BAR_POS_INVALID) {
- return false;
- }
- int createMode = navbarPos == NAV_BAR_POS_LEFT
- ? SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT
- : SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
- return mRecentsOptional.get().splitPrimaryTask(createMode, null, metricsDockAction);
- } else {
- if (divider.isMinimized() && !divider.isHomeStackResizable()) {
- // Undocking from the minimized state is not supported
- return false;
- } else {
- divider.onUndockingTask();
- if (metricsUndockAction != -1) {
- mMetricsLogger.action(metricsUndockAction);
+
+ if (mSplitScreenOptional.isPresent()) {
+ SplitScreen splitScreen = mSplitScreenOptional.get();
+ if (splitScreen.isDividerVisible()) {
+ if (splitScreen.isMinimized()
+ && !splitScreen.isHomeStackResizable()) {
+ // Undocking from the minimized state is not supported
+ return false;
+ } else {
+ splitScreen.onUndockingTask();
+ if (metricsUndockAction != -1) {
+ mMetricsLogger.action(metricsUndockAction);
+ }
}
+ return true;
}
}
- return true;
+
+ final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition(mDisplayId);
+ if (navbarPos == NAV_BAR_POS_INVALID) {
+ return false;
+ }
+ int createMode = navbarPos == NAV_BAR_POS_LEFT
+ ? SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT
+ : SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
+ return mRecentsOptional.get().splitPrimaryTask(createMode, null, metricsDockAction);
}
/**
@@ -3916,14 +3917,14 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void appTransitionCancelled(int displayId) {
if (displayId == mDisplayId) {
- mDividerOptional.ifPresent(Divider::onAppTransitionFinished);
+ mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.onAppTransitionFinished());
}
}
@Override
public void appTransitionFinished(int displayId) {
if (displayId == mDisplayId) {
- mDividerOptional.ifPresent(Divider::onAppTransitionFinished);
+ mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.onAppTransitionFinished());
}
}
@@ -4221,25 +4222,6 @@ public class StatusBar extends SystemUI implements DemoMode,
KeyboardShortcuts.dismiss();
}
- /**
- * Called when the notification panel layouts
- */
- public void onPanelLaidOut() {
- updateKeyguardMaxNotifications();
- }
-
- public void updateKeyguardMaxNotifications() {
- if (mState == StatusBarState.KEYGUARD) {
- // Since the number of notifications is determined based on the height of the view, we
- // need to update them.
- int maxBefore = mPresenter.getMaxNotificationsWhileLocked(false /* recompute */);
- int maxNotifications = mPresenter.getMaxNotificationsWhileLocked(true /* recompute */);
- if (maxBefore != maxNotifications) {
- mViewHierarchyManager.updateRowStates();
- }
- }
- }
-
public void executeActionDismissingKeyguard(Runnable action, boolean afterKeyguardGone) {
if (!mDeviceProvisionedController.isDeviceProvisioned()) return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 7ee501c681f9..777bf3f73480 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -50,6 +50,7 @@ import com.android.systemui.SystemUIFactory;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -68,6 +69,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Optional;
import javax.inject.Inject;
@@ -103,6 +105,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private final ConfigurationController mConfigurationController;
private final NavigationModeController mNavigationModeController;
private final NotificationShadeWindowController mNotificationShadeWindowController;
+ private final Optional<FaceAuthScreenBrightnessController> mFaceAuthScreenBrightnessController;
private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() {
@Override
public void onFullyShown() {
@@ -212,6 +215,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
DockManager dockManager,
NotificationShadeWindowController notificationShadeWindowController,
KeyguardStateController keyguardStateController,
+ Optional<FaceAuthScreenBrightnessController> faceAuthScreenBrightnessController,
NotificationMediaManager notificationMediaManager) {
mContext = context;
mViewMediatorCallback = callback;
@@ -224,6 +228,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mKeyguardUpdateManager = keyguardUpdateMonitor;
mStatusBarStateController = sysuiStatusBarStateController;
mDockManager = dockManager;
+ mFaceAuthScreenBrightnessController = faceAuthScreenBrightnessController;
}
@Override
@@ -248,6 +253,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
notificationPanelViewController.addExpansionListener(this);
mBypassController = bypassController;
mNotificationContainer = notificationContainer;
+ mFaceAuthScreenBrightnessController.ifPresent((it) -> {
+ View overlay = new View(mContext);
+ container.addView(overlay);
+ it.attach(overlay);
+ });
registerListeners();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 67adaaae402e..024a0b17b5cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -110,7 +110,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
private final AboveShelfObserver mAboveShelfObserver;
private final DozeScrimController mDozeScrimController;
private final ScrimController mScrimController;
- private final Context mContext;
private final KeyguardIndicationController mKeyguardIndicationController;
private final StatusBar mStatusBar;
private final ShadeController mShadeController;
@@ -119,7 +118,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
private final AccessibilityManager mAccessibilityManager;
private final KeyguardManager mKeyguardManager;
private final ActivityLaunchAnimator mActivityLaunchAnimator;
- private final int mMaxAllowedKeyguardNotifications;
private final IStatusBarService mBarService;
private final DynamicPrivacyController mDynamicPrivacyController;
private boolean mReinflateNotificationsOnUserSwitched;
@@ -127,7 +125,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
private TextView mNotificationPanelDebugText;
protected boolean mVrMode;
- private int mMaxKeyguardNotifications;
public StatusBarNotificationPresenter(Context context,
NotificationPanelViewController panel,
@@ -145,7 +142,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
CommandQueue commandQueue,
InitController initController,
NotificationInterruptStateProvider notificationInterruptStateProvider) {
- mContext = context;
mKeyguardStateController = keyguardStateController;
mNotificationPanel = panel;
mHeadsUpManager = headsUp;
@@ -163,8 +159,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
mDozeScrimController = dozeScrimController;
mScrimController = scrimController;
mKeyguardManager = context.getSystemService(KeyguardManager.class);
- mMaxAllowedKeyguardNotifications = context.getResources().getInteger(
- R.integer.keyguard_max_notification_count);
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
@@ -397,17 +391,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
}
@Override
- public int getMaxNotificationsWhileLocked(boolean recompute) {
- if (recompute) {
- mMaxKeyguardNotifications = Math.max(1,
- mNotificationPanel.computeMaxKeyguardNotifications(
- mMaxAllowedKeyguardNotifications));
- return mMaxKeyguardNotifications;
- }
- return mMaxKeyguardNotifications;
- }
-
- @Override
public void onUpdateRowStates() {
mNotificationPanel.onUpdateRowStates();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 2768b826fcfe..72067d376f7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -46,7 +46,7 @@ import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -180,7 +180,7 @@ public interface StatusBarPhoneModule {
Optional<Recents> recentsOptional,
Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
- Optional<Divider> dividerOptional,
+ Optional<SplitScreen> splitScreenOptional,
LightsOutNotifController lightsOutNotifController,
StatusBarNotificationActivityStarter.Builder
statusBarNotificationActivityStarterBuilder,
@@ -260,7 +260,7 @@ public interface StatusBarPhoneModule {
recentsOptional,
statusBarComponentBuilder,
pluginManager,
- dividerOptional,
+ splitScreenOptional,
lightsOutNotifController,
statusBarNotificationActivityStarterBuilder,
shadeController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 33b1a4a880ae..f39acf9a40ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -39,6 +39,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dump.DumpManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -58,6 +59,7 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
private static final String TAG = "BluetoothController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private final DumpManager mDumpManager;
private final LocalBluetoothManager mLocalBluetoothManager;
private final UserManager mUserManager;
private final int mCurrentUser;
@@ -77,8 +79,13 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
/**
*/
@Inject
- public BluetoothControllerImpl(Context context, @Background Looper bgLooper,
- @Main Looper mainLooper, @Nullable LocalBluetoothManager localBluetoothManager) {
+ public BluetoothControllerImpl(
+ Context context,
+ DumpManager dumpManager,
+ @Background Looper bgLooper,
+ @Main Looper mainLooper,
+ @Nullable LocalBluetoothManager localBluetoothManager) {
+ mDumpManager = dumpManager;
mLocalBluetoothManager = localBluetoothManager;
mBgHandler = new Handler(bgLooper);
mHandler = new H(mainLooper);
@@ -90,6 +97,7 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
}
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mCurrentUser = ActivityManager.getCurrentUser();
+ mDumpManager.registerDumpable(TAG, this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
index b7bc8c8fb7c4..302301d79c3a 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
@@ -24,7 +24,6 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.SystemServicesModule;
import com.android.systemui.dagger.SystemUIBinder;
import com.android.systemui.dagger.SystemUIModule;
-import com.android.systemui.onehanded.dagger.OneHandedModule;
import dagger.Subcomponent;
@@ -36,7 +35,6 @@ import dagger.Subcomponent;
DefaultComponentBinder.class,
DependencyProvider.class,
DependencyBinder.class,
- OneHandedModule.class,
SystemServicesModule.class,
SystemUIBinder.class,
SystemUIModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index ca9cb08c0a59..e7c10f1697f5 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -42,7 +42,6 @@ import com.android.systemui.qs.dagger.QSModule;
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImplementation;
-import com.android.systemui.stackdivider.DividerModule;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
@@ -76,7 +75,6 @@ import dagger.Provides;
* overridden by the System UI implementation.
*/
@Module(includes = {
- DividerModule.class,
QSModule.class,
WMShellModule.class
},
diff --git a/packages/SystemUI/src/com/android/systemui/util/DeviceConfigProxy.java b/packages/SystemUI/src/com/android/systemui/util/DeviceConfigProxy.java
index 3a2172ae0fae..66f8f74c7cab 100644
--- a/packages/SystemUI/src/com/android/systemui/util/DeviceConfigProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/util/DeviceConfigProxy.java
@@ -25,13 +25,11 @@ import android.provider.Settings;
import java.util.concurrent.Executor;
-import javax.inject.Inject;
-
/**
* Wrapper around DeviceConfig useful for testing.
*/
public class DeviceConfigProxy {
- @Inject
+
public DeviceConfigProxy() {
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt
index f22f59bee42f..bcfb2afeeda1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt
@@ -4,8 +4,7 @@ import android.graphics.Rect
import android.util.Log
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.FloatingContentCoordinator.FloatingContent
-import java.util.*
-import javax.inject.Inject
+import java.util.HashMap
/** Tag for debug logging. */
private const val TAG = "FloatingCoordinator"
@@ -20,9 +19,9 @@ private const val TAG = "FloatingCoordinator"
* other content out of the way. [onContentRemoved] should be called when the content is removed or
* no longer visible.
*/
-@SysUISingleton
-class FloatingContentCoordinator @Inject constructor() {
+@SysUISingleton
+class FloatingContentCoordinator constructor() {
/**
* Represents a piece of floating content, such as PIP or the Bubbles stack. Provides methods
* that allow the [FloatingContentCoordinator] to determine the current location of the content,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
new file mode 100644
index 000000000000..49226000e97d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -0,0 +1,111 @@
+/*
+ * 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.wmshell;
+
+import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+
+import android.app.ActivityManager;
+import android.content.Context;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.SystemUI;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.stackdivider.SplitScreen;
+import com.android.wm.shell.common.DisplayImeController;
+
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+/**
+ * Proxy in SysUiScope to delegate events to controllers in WM Shell library.
+ */
+@SysUISingleton
+public final class WMShell extends SystemUI {
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final DisplayImeController mDisplayImeController;
+ private final Optional<SplitScreen> mSplitScreenOptional;
+
+ @Inject
+ WMShell(Context context, KeyguardUpdateMonitor keyguardUpdateMonitor,
+ DisplayImeController displayImeController,
+ Optional<SplitScreen> splitScreenOptional) {
+ super(context);
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mDisplayImeController = displayImeController;
+ mSplitScreenOptional = splitScreenOptional;
+ }
+
+ @Override
+ public void start() {
+ // This is to prevent circular init problem by separating registration step out of its
+ // constructor. And make sure the initialization of DisplayImeController won't depend on
+ // specific feature anymore.
+ mDisplayImeController.startMonitorDisplays();
+
+ mSplitScreenOptional.ifPresent(this::initSplitScreen);
+ }
+
+ private void initSplitScreen(SplitScreen splitScreen) {
+ mKeyguardUpdateMonitor.registerCallback(new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ // Hide the divider when keyguard is showing. Even though keyguard/statusbar is
+ // above everything, it is actually transparent except for notifications, so
+ // we still need to hide any surfaces that are below it.
+ // TODO(b/148906453): Figure out keyguard dismiss animation for divider view.
+ splitScreen.onKeyguardVisibilityChanged(showing);
+ }
+ });
+
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(
+ new TaskStackChangeListener() {
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+ if (!wasVisible || task.configuration.windowConfiguration.getWindowingMode()
+ != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || !splitScreen.isSplitScreenSupported()) {
+ return;
+ }
+
+ if (splitScreen.isMinimized()) {
+ splitScreen.onUndockingTask();
+ }
+ }
+
+ @Override
+ public void onActivityForcedResizable(String packageName, int taskId,
+ int reason) {
+ splitScreen.onActivityForcedResizable(packageName, taskId, reason);
+ }
+
+ @Override
+ public void onActivityDismissingDockedStack() {
+ splitScreen.onActivityDismissingSplitScreen();
+ }
+
+ @Override
+ public void onActivityLaunchOnSecondaryDisplayFailed() {
+ splitScreen.onActivityLaunchOnSecondaryDisplayFailed();
+ }
+ });
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index ac47660f3221..0a3172ce4eb6 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -20,12 +20,19 @@ import android.content.Context;
import android.os.Handler;
import android.view.IWindowManager;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.pip.PipUiEventLogger;
+import com.android.systemui.stackdivider.SplitScreen;
+import com.android.systemui.util.DeviceConfigProxy;
+import com.android.systemui.util.FloatingContentCoordinator;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
+import dagger.BindsOptionalOf;
import dagger.Module;
import dagger.Provides;
@@ -35,7 +42,7 @@ import dagger.Provides;
*/
// TODO(b/162923491): Move most of these dependencies into WMSingleton scope.
@Module
-public class WMShellBaseModule {
+public abstract class WMShellBaseModule {
@SysUISingleton
@Provides
static TransactionPool provideTransactionPool() {
@@ -51,8 +58,37 @@ public class WMShellBaseModule {
@SysUISingleton
@Provides
+ static DeviceConfigProxy provideDeviceConfigProxy() {
+ return new DeviceConfigProxy();
+ }
+
+ @SysUISingleton
+ @Provides
+ static FloatingContentCoordinator provideFloatingContentCoordinator() {
+ return new FloatingContentCoordinator();
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipUiEventLogger providePipUiEventLogger(UiEventLogger uiEventLogger) {
+ return new PipUiEventLogger(uiEventLogger);
+ }
+
+ @SysUISingleton
+ @Provides
static SystemWindows provideSystemWindows(DisplayController displayController,
IWindowManager wmService) {
return new SystemWindows(displayController, wmService);
}
+
+ @SysUISingleton
+ @Provides
+ static ShellTaskOrganizer provideShellTaskOrganizer() {
+ ShellTaskOrganizer organizer = new ShellTaskOrganizer();
+ organizer.registerOrganizer();
+ return organizer;
+ }
+
+ @BindsOptionalOf
+ abstract SplitScreen optionalSplitScreen();
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 44bb6ac5a49c..7b4547689c8b 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -16,6 +16,7 @@
package com.android.systemui.wmshell;
+import android.content.Context;
import android.os.Handler;
import android.view.IWindowManager;
@@ -23,8 +24,12 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.pip.phone.PipMenuActivity;
import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
+import com.android.systemui.stackdivider.SplitScreen;
+import com.android.systemui.stackdivider.SplitScreenController;
+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.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
import dagger.Module;
@@ -42,8 +47,7 @@ public class WMShellModule {
static DisplayImeController provideDisplayImeController(IWindowManager wmService,
DisplayController displayController, @Main Handler mainHandler,
TransactionPool transactionPool) {
- return new DisplayImeController.Builder(wmService, displayController, mainHandler,
- transactionPool).build();
+ return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
}
/** TODO(b/150319024): PipMenuActivity will move to a Window */
@@ -53,4 +57,14 @@ public class WMShellModule {
static Class<?> providePipMenuActivityClass() {
return PipMenuActivity.class;
}
+
+ @SysUISingleton
+ @Provides
+ static SplitScreen provideSplitScreen(Context context,
+ DisplayController displayController, SystemWindows systemWindows,
+ DisplayImeController displayImeController, @Main Handler handler,
+ TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer) {
+ return new SplitScreenController(context, displayController, systemWindows,
+ displayImeController, handler, transactionPool, shellTaskOrganizer);
+ }
}
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index c6331682f80c..db878458721e 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -80,6 +80,8 @@
android:excludeFromRecents="true"
/>
+ <activity android:name="com.android.systemui.screenshot.ScrollViewActivity"
+ android:exported="false" />
<provider
android:name="androidx.lifecycle.ProcessLifecycleOwnerInitializer"
tools:replace="android:authorities"
diff --git a/packages/SystemUI/tests/res/values/strings.xml b/packages/SystemUI/tests/res/values/strings.xml
new file mode 100644
index 000000000000..b9f24c881813
--- /dev/null
+++ b/packages/SystemUI/tests/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <string name="test_content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ultrices condimentum ultricies. Sed elementum at massa id sagittis. Nullam dictum massa lorem, nec ornare nunc pharetra vitae. Duis ultrices, felis eu condimentum congue, erat orci efficitur purus, ac rutrum odio lacus sed sapien. Suspendisse erat augue, eleifend eget auctor sagittis, porta eget nibh. Mauris pulvinar urna non justo condimentum, ut vehicula sapien finibus. Aliquam nibh magna, tincidunt ut viverra sed, placerat et turpis. Nam placerat, dui sed tincidunt consectetur, ante velit posuere mauris, tincidunt finibus velit lectus ac tortor. Cras eget lectus feugiat, porttitor velit nec, malesuada massa.</string>
+
+</resources>
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt
index 861c6207f5b0..690b9a7248be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt
@@ -25,6 +25,7 @@ import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import org.junit.After
import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -78,4 +79,15 @@ class ControlsFavoritePersistenceWrapperTest : SysuiTestCase() {
assertEquals(list, wrapper.readFavorites())
}
+
+ @Test
+ fun testSaveEmptyOnNonExistingFile() {
+ if (file.exists()) {
+ file.delete()
+ }
+
+ wrapper.storeFavorites(emptyList())
+
+ assertFalse(file.exists())
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt
new file mode 100644
index 000000000000..58cb0324c69a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt
@@ -0,0 +1,135 @@
+/*
+ * 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.keyguard
+
+import android.animation.ValueAnimator
+import android.content.res.Resources
+import android.hardware.biometrics.BiometricSourceType
+import android.os.Handler
+import android.provider.Settings.System.SCREEN_BRIGHTNESS_FLOAT
+import android.testing.AndroidTestingRunner
+import android.util.TypedValue
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.Dumpable
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.settings.GlobalSettings
+import com.android.systemui.util.settings.SystemSettings
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+const val INITIAL_BRIGHTNESS = 0.5f
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class FaceAuthScreenBrightnessControllerTest : SysuiTestCase() {
+
+ @Mock
+ lateinit var whiteOverlay: View
+ @Mock
+ lateinit var dumpManager: DumpManager
+ @Mock
+ lateinit var resources: Resources
+ @Mock
+ lateinit var mainHandler: Handler
+ @Mock
+ lateinit var globalSettings: GlobalSettings
+ @Mock
+ lateinit var systemSettings: SystemSettings
+ @Mock
+ lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock
+ lateinit var notificationShadeWindowController: NotificationShadeWindowController
+ @Mock
+ lateinit var animator: ValueAnimator
+ @Captor
+ lateinit var keyguardUpdateCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>
+ lateinit var faceAuthScreenBrightnessController: FaceAuthScreenBrightnessController
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ faceAuthScreenBrightnessController = object : FaceAuthScreenBrightnessController(
+ notificationShadeWindowController, keyguardUpdateMonitor, resources, globalSettings,
+ systemSettings, mainHandler, dumpManager) {
+ override fun createAnimator(start: Float, end: Float) = animator
+ }
+ `when`(systemSettings.getFloat(eq(SCREEN_BRIGHTNESS_FLOAT))).thenReturn(INITIAL_BRIGHTNESS)
+ faceAuthScreenBrightnessController.attach(whiteOverlay)
+ verify(keyguardUpdateMonitor).registerCallback(capture(keyguardUpdateCallback))
+ }
+
+ @Test
+ fun init_registersDumpManager() {
+ verify(dumpManager).registerDumpable(anyString(), any(Dumpable::class.java))
+ }
+
+ @Test
+ fun init_registersKeyguardCallback() {
+ verify(keyguardUpdateMonitor)
+ .registerCallback(any(KeyguardUpdateMonitorCallback::class.java))
+ }
+
+ @Test
+ fun onBiometricRunningChanged_animatesBrightness() {
+ clearInvocations(whiteOverlay)
+ keyguardUpdateCallback.value
+ .onBiometricRunningStateChanged(true, BiometricSourceType.FACE)
+ verify(whiteOverlay).visibility = eq(View.VISIBLE)
+ verify(animator).start()
+ }
+
+ @Test
+ fun faceAuthWallpaper_whenFaceIsDisabledForUser() {
+ faceAuthScreenBrightnessController.useFaceAuthWallpaper = true
+ faceAuthScreenBrightnessController.faceAuthWallpaper
+ verify(resources, never()).openRawResource(anyInt(), any(TypedValue::class.java))
+ }
+
+ @Test
+ fun faceAuthWallpaper_whenFaceFlagIsDisabled() {
+ faceAuthScreenBrightnessController.useFaceAuthWallpaper = true
+ faceAuthScreenBrightnessController.faceAuthWallpaper
+ verify(resources, never()).openRawResource(anyInt(), any(TypedValue::class.java))
+ }
+
+ @Test
+ fun faceAuthWallpaper_whenFaceIsEnabledForUser() {
+ faceAuthScreenBrightnessController.useFaceAuthWallpaper = true
+ `when`(keyguardUpdateMonitor.isFaceAuthEnabledForUser(anyInt())).thenReturn(true)
+ faceAuthScreenBrightnessController.faceAuthWallpaper
+ verify(resources).openRawResource(anyInt(), any(TypedValue::class.java))
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
index ca8f79d08ef0..da1ec9869d87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
@@ -21,6 +21,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
@@ -59,6 +60,7 @@ public class MediaPlayerDataTest : SysuiTestCase() {
}
@Test
+ @Ignore("Flaky")
fun switchPlayersPlaying() {
val playerIsPlaying1 = mock(MediaControlPanel::class.java)
whenever(playerIsPlaying1.isPlaying).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
index 7a8e4f7e9b85..f38524369b46 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
@@ -155,6 +155,22 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
}
@Test
+ fun testOnMediaDataLoaded_migratesKeys_noTimeoutExtension() {
+ // From not playing
+ mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
+ clearInvocations(mediaController)
+
+ // Migrate, still not playing
+ val playingState = mock(android.media.session.PlaybackState::class.java)
+ `when`(playingState.state).thenReturn(PlaybackState.STATE_PAUSED)
+ `when`(mediaController.playbackState).thenReturn(playingState)
+ mediaTimeoutListener.onMediaDataLoaded("NEWKEY", KEY, mediaData)
+
+ // Never cancels callback, or schedule another one
+ verify(cancellationRunnable, never()).run()
+ }
+
+ @Test
fun testOnPlaybackStateChanged_schedulesTimeout_whenPaused() {
// Assuming we're registered
testOnMediaDataLoaded_registersPlaybackListener()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index 2e4d8a7ff472..57dbac5bfb10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -52,7 +52,7 @@ 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.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -61,13 +61,13 @@ import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import java.util.Optional;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Optional;
+
/** atest NavigationBarControllerTest */
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -90,13 +90,13 @@ public class NavigationBarControllerTest extends SysuiTestCase {
mock(AccessibilityManagerWrapper.class),
mock(DeviceProvisionedController.class),
mock(MetricsLogger.class),
- mock(OverviewProxyService.class),
+ mock(OverviewProxyService.class),
mock(NavigationModeController.class),
mock(StatusBarStateController.class),
mock(SysUiState.class),
mock(BroadcastDispatcher.class),
mock(CommandQueue.class),
- mock(Divider.class),
+ Optional.of(mock(SplitScreen.class)),
Optional.of(mock(Recents.class)),
() -> mock(StatusBar.class),
mock(ShadeController.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index a643c2dc0f19..389c5a08b7c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -68,7 +68,7 @@ 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.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -121,7 +121,6 @@ public class NavigationBarTest extends SysuiTestCase {
mDependency.injectMockDependency(KeyguardStateController.class);
mDependency.injectMockDependency(StatusBarStateController.class);
mDependency.injectMockDependency(NavigationBarController.class);
- mDependency.injectMockDependency(Divider.class);
mOverviewProxyService = mDependency.injectMockDependency(OverviewProxyService.class);
TestableLooper.get(this).runWithLooper(() -> {
mHandler = new Handler();
@@ -224,7 +223,7 @@ public class NavigationBarTest extends SysuiTestCase {
mMockSysUiState,
mBroadcastDispatcher,
mCommandQueue,
- mock(Divider.class),
+ Optional.of(mock(SplitScreen.class)),
Optional.of(mock(Recents.class)),
() -> mock(StatusBar.class),
mock(ShadeController.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedControllerTest.java
index d7dba5fdf8c8..02d587d90655 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedControllerTest.java
@@ -46,9 +46,9 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class OneHandedManagerImplTest extends OneHandedTestCase {
+public class OneHandedControllerTest extends OneHandedTestCase {
Display mDisplay;
- OneHandedManagerImpl mOneHandedManagerImpl;
+ OneHandedController mOneHandedController;
OneHandedTimeoutHandler mTimeoutHandler;
@Mock
@@ -70,7 +70,7 @@ public class OneHandedManagerImplTest extends OneHandedTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mDisplay = mContext.getDisplay();
- mOneHandedManagerImpl = new OneHandedManagerImpl(
+ mOneHandedController = new OneHandedController(
getContext(),
mCommandQueue,
mMockDisplayController,
@@ -102,7 +102,7 @@ public class OneHandedManagerImplTest extends OneHandedTestCase {
@Test
public void testStartOneHanded() {
- mOneHandedManagerImpl.startOneHanded();
+ mOneHandedController.startOneHanded();
verify(mMockDisplayAreaOrganizer).scheduleOffset(anyInt(), anyInt());
}
@@ -110,7 +110,7 @@ public class OneHandedManagerImplTest extends OneHandedTestCase {
@Test
public void testStopOneHanded() {
when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false);
- mOneHandedManagerImpl.stopOneHanded();
+ mOneHandedController.stopOneHanded();
verify(mMockDisplayAreaOrganizer, never()).scheduleOffset(anyInt(), anyInt());
}
@@ -122,7 +122,7 @@ public class OneHandedManagerImplTest extends OneHandedTestCase {
@Test
public void testStopOneHanded_shouldRemoveTimer() {
- mOneHandedManagerImpl.stopOneHanded();
+ mOneHandedController.stopOneHanded();
verify(mTimeoutHandler).removeTimer();
}
@@ -130,7 +130,7 @@ public class OneHandedManagerImplTest extends OneHandedTestCase {
@Test
public void testUpdateIsEnabled() {
final boolean enabled = true;
- mOneHandedManagerImpl.setOneHandedEnabled(enabled);
+ mOneHandedController.setOneHandedEnabled(enabled);
verify(mMockTouchHandler, times(2)).onOneHandedEnabled(enabled);
}
@@ -138,7 +138,7 @@ public class OneHandedManagerImplTest extends OneHandedTestCase {
@Test
public void testUpdateSwipeToNotificationIsEnabled() {
final boolean enabled = true;
- mOneHandedManagerImpl.setSwipeToNotificationEnabled(enabled);
+ mOneHandedController.setSwipeToNotificationEnabled(enabled);
verify(mMockTouchHandler, times(2)).onOneHandedEnabled(enabled);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java
index 95a230f6511c..756382a6c630 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java
@@ -30,8 +30,8 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.model.SysUiState;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.wm.shell.common.DisplayController;
import org.junit.Before;
@@ -48,7 +48,7 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase {
OneHandedTouchHandler mTouchHandler;
OneHandedTutorialHandler mTutorialHandler;
OneHandedGestureHandler mGestureHandler;
- OneHandedManagerImpl mOneHandedManagerImpl;
+ OneHandedController mOneHandedController;
@Mock
CommandQueue mCommandQueue;
@Mock
@@ -66,7 +66,7 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase {
mTutorialHandler = new OneHandedTutorialHandler(mContext);
mGestureHandler = Mockito.spy(new OneHandedGestureHandler(
mContext, mMockDisplayController, mMockNavigationModeController));
- mOneHandedManagerImpl = new OneHandedManagerImpl(
+ mOneHandedController = new OneHandedController(
getContext(),
mCommandQueue,
mMockDisplayController,
@@ -93,15 +93,15 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase {
public void testReceiveNewConfig_whenSetOneHandedEnabled() {
// 1st called at init
verify(mGestureHandler).onOneHandedEnabled(true);
- mOneHandedManagerImpl.setOneHandedEnabled(true);
+ mOneHandedController.setOneHandedEnabled(true);
// 2nd called by setOneHandedEnabled()
verify(mGestureHandler, times(2)).onOneHandedEnabled(true);
}
@Test
public void testOneHandedDisabled_shouldDisposeInputChannel() {
- mOneHandedManagerImpl.setOneHandedEnabled(false);
- mOneHandedManagerImpl.setSwipeToNotificationEnabled(false);
+ mOneHandedController.setOneHandedEnabled(false);
+ mOneHandedController.setSwipeToNotificationEnabled(false);
assertThat(mGestureHandler.mInputMonitor).isNull();
assertThat(mGestureHandler.mInputEventReceiver).isNull();
@@ -111,7 +111,7 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase {
public void testChangeNavBarTo2Button_shouldDisposeInputChannel() {
// 1st called at init
verify(mGestureHandler).onOneHandedEnabled(true);
- mOneHandedManagerImpl.setOneHandedEnabled(true);
+ mOneHandedController.setOneHandedEnabled(true);
// 2nd called by setOneHandedEnabled()
verify(mGestureHandler, times(2)).onOneHandedEnabled(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java
index 8ae632dd5a47..3c3ace052e47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java
@@ -28,8 +28,8 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.model.SysUiState;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.wm.shell.common.DisplayController;
import org.junit.Before;
@@ -46,7 +46,7 @@ public class OneHandedTouchHandlerTest extends OneHandedTestCase {
OneHandedTouchHandler mTouchHandler;
OneHandedTutorialHandler mTutorialHandler;
OneHandedGestureHandler mGestureHandler;
- OneHandedManagerImpl mOneHandedManagerImpl;
+ OneHandedController mOneHandedController;
@Mock
CommandQueue mCommandQueue;
@Mock
@@ -64,7 +64,7 @@ public class OneHandedTouchHandlerTest extends OneHandedTestCase {
mTouchHandler = Mockito.spy(new OneHandedTouchHandler());
mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController,
mMockNavigationModeController);
- mOneHandedManagerImpl = new OneHandedManagerImpl(
+ mOneHandedController = new OneHandedController(
getContext(),
mCommandQueue,
mMockDisplayController,
@@ -88,14 +88,14 @@ public class OneHandedTouchHandlerTest extends OneHandedTestCase {
@Test
public void testOneHandedDisabled_shouldDisposeInputChannel() {
- mOneHandedManagerImpl.setOneHandedEnabled(false);
+ mOneHandedController.setOneHandedEnabled(false);
assertThat(mTouchHandler.mInputMonitor).isNull();
assertThat(mTouchHandler.mInputEventReceiver).isNull();
}
@Test
public void testOneHandedEnabled_monitorInputChannel() {
- mOneHandedManagerImpl.setOneHandedEnabled(true);
+ mOneHandedController.setOneHandedEnabled(true);
assertThat(mTouchHandler.mInputMonitor).isNotNull();
assertThat(mTouchHandler.mInputEventReceiver).isNotNull();
}
@@ -104,7 +104,7 @@ public class OneHandedTouchHandlerTest extends OneHandedTestCase {
public void testReceiveNewConfig_whenSetOneHandedEnabled() {
// 1st called at init
verify(mTouchHandler).onOneHandedEnabled(true);
- mOneHandedManagerImpl.setOneHandedEnabled(true);
+ mOneHandedController.setOneHandedEnabled(true);
// 2nd called by setOneHandedEnabled()
verify(mTouchHandler, times(2)).onOneHandedEnabled(true);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java
index c75a8d2f5454..1bffbf7eb8dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java
@@ -24,8 +24,8 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.model.SysUiState;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.wm.shell.common.DisplayController;
import org.junit.Before;
@@ -42,7 +42,7 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
OneHandedTouchHandler mTouchHandler;
OneHandedTutorialHandler mTutorialHandler;
OneHandedGestureHandler mGestureHandler;
- OneHandedManagerImpl mOneHandedManagerImpl;
+ OneHandedController mOneHandedController;
@Mock
CommandQueue mCommandQueue;
@Mock
@@ -61,7 +61,7 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
mTutorialHandler = Mockito.spy(new OneHandedTutorialHandler(mContext));
mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController,
mMockNavigationModeController);
- mOneHandedManagerImpl = new OneHandedManagerImpl(
+ mOneHandedController = new OneHandedController(
getContext(),
mCommandQueue,
mMockDisplayController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java
index f0e713e42046..ae3df5db30bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java
@@ -48,7 +48,7 @@ public class OneHandedUITest extends OneHandedTestCase {
OneHandedUI mOneHandedUI;
ScreenLifecycle mScreenLifecycle;
@Mock
- OneHandedManagerImpl mMockOneHandedManagerImpl;
+ OneHandedController mOneHandedController;
@Mock
OneHandedTimeoutHandler mMockTimeoutHandler;
@@ -59,7 +59,7 @@ public class OneHandedUITest extends OneHandedTestCase {
mScreenLifecycle = new ScreenLifecycle();
mOneHandedUI = new OneHandedUI(mContext,
mCommandQueue,
- mMockOneHandedManagerImpl,
+ mOneHandedController,
mScreenLifecycle);
mOneHandedUI.start();
mKeyguardUpdateMonitor = mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
@@ -74,14 +74,14 @@ public class OneHandedUITest extends OneHandedTestCase {
public void testStartOneHanded() {
mOneHandedUI.startOneHanded();
- verify(mMockOneHandedManagerImpl).startOneHanded();
+ verify(mOneHandedController).startOneHanded();
}
@Test
public void testStopOneHanded() {
mOneHandedUI.stopOneHanded();
- verify(mMockOneHandedManagerImpl).stopOneHanded();
+ verify(mOneHandedController).stopOneHanded();
}
@Test
@@ -89,7 +89,7 @@ public class OneHandedUITest extends OneHandedTestCase {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.TAPS_APP_TO_EXIT, 1);
- verify(mMockOneHandedManagerImpl).setTaskChangeToExit(true);
+ verify(mOneHandedController).setTaskChangeToExit(true);
}
@Test
@@ -97,7 +97,7 @@ public class OneHandedUITest extends OneHandedTestCase {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ONE_HANDED_MODE_ENABLED, 1);
- verify(mMockOneHandedManagerImpl).setOneHandedEnabled(true);
+ verify(mOneHandedController).setOneHandedEnabled(true);
}
@Test
@@ -115,7 +115,7 @@ public class OneHandedUITest extends OneHandedTestCase {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1);
- verify(mMockOneHandedManagerImpl).setSwipeToNotificationEnabled(true);
+ verify(mOneHandedController).setSwipeToNotificationEnabled(true);
}
@Ignore("Clarifying do not receive callback")
@@ -123,14 +123,14 @@ public class OneHandedUITest extends OneHandedTestCase {
public void testKeyguardBouncerShowing_shouldStopOneHanded() {
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true);
- verify(mMockOneHandedManagerImpl).stopOneHanded();
+ verify(mOneHandedController).stopOneHanded();
}
@Test
public void testScreenTurningOff_shouldStopOneHanded() {
mScreenLifecycle.dispatchScreenTurningOff();
- verify(mMockOneHandedManagerImpl).stopOneHanded();
+ verify(mOneHandedController).stopOneHanded();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
index e9d2b73182e0..cdb177096f11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
@@ -19,7 +19,6 @@ package com.android.systemui.pip;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
import android.content.ComponentName;
import android.graphics.Rect;
@@ -33,7 +32,6 @@ import android.view.Gravity;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.wm.shell.common.DisplayController;
import org.junit.Before;
import org.junit.Test;
@@ -65,8 +63,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
initializeMockResources();
- mPipBoundsHandler = new PipBoundsHandler(mContext, new PipSnapAlgorithm(mContext),
- mock(DisplayController.class));
+ mPipBoundsHandler = new PipBoundsHandler(mContext);
mTestComponentName1 = new ComponentName(mContext, "component1");
mTestComponentName2 = new ComponentName(mContext, "component2");
@@ -113,7 +110,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase {
res.addOverride(com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio,
newDefaultAspectRatio);
- mPipBoundsHandler.onConfigurationChanged();
+ mPipBoundsHandler.onConfigurationChanged(mContext);
assertEquals("Default aspect ratio should be reloaded",
mPipBoundsHandler.getDefaultAspectRatio(), newDefaultAspectRatio,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
index 9f67722041aa..c8d4aca90519 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
@@ -72,9 +72,6 @@ public class PipTouchHandlerTest extends SysuiTestCase {
private InputConsumerController mInputConsumerController;
@Mock
- private PipBoundsHandler mPipBoundsHandler;
-
- @Mock
private PipTaskOrganizer mPipTaskOrganizer;
@Mock
@@ -89,6 +86,7 @@ public class PipTouchHandlerTest extends SysuiTestCase {
@Mock
private PipUiEventLogger mPipUiEventLogger;
+ private PipBoundsHandler mPipBoundsHandler;
private PipSnapAlgorithm mPipSnapAlgorithm;
private PipMotionHelper mMotionHelper;
private PipResizeGestureHandler mPipResizeGestureHandler;
@@ -104,11 +102,13 @@ public class PipTouchHandlerTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mPipBoundsHandler = new PipBoundsHandler(mContext);
+ mPipSnapAlgorithm = mPipBoundsHandler.getSnapAlgorithm();
mPipSnapAlgorithm = new PipSnapAlgorithm(mContext);
mPipTouchHandler = new PipTouchHandler(mContext, mActivityManager,
mPipMenuActivityController, mInputConsumerController, mPipBoundsHandler,
- mPipTaskOrganizer, mFloatingContentCoordinator, mDeviceConfigProxy,
- mPipSnapAlgorithm, mSysUiState, mPipUiEventLogger);
+ mPipTaskOrganizer, mFloatingContentCoordinator, mDeviceConfigProxy, mSysUiState,
+ mPipUiEventLogger);
mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler());
mPipTouchHandler.setPipMotionHelper(mMotionHelper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureTest.java
new file mode 100644
index 000000000000..e7ef64e6adad
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.screenshot;
+
+import static org.junit.Assert.fail;
+
+import android.content.Intent;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.testing.AndroidTestingRunner;
+import android.util.Log;
+import android.view.Display;
+import android.view.IScrollCaptureClient;
+import android.view.IScrollCaptureController;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests the of internal framework Scroll Capture API from SystemUI.
+ */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class ScrollCaptureTest extends SysuiTestCase {
+ private static final String TAG = "ScrollCaptureTest";
+
+ /**
+ * Verifies that a request traverses from SystemUI, to WindowManager and to the app process and
+ * is returned without error. Device must be unlocked.
+ */
+ @Test
+ public void testBasicOperation() throws InterruptedException {
+ IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
+
+ // Start an activity to be on top that will be targeted
+ InstrumentationRegistry.getInstrumentation().startActivitySync(
+ new Intent(mContext, ScrollViewActivity.class).addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK));
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ try {
+ wms.requestScrollCapture(Display.DEFAULT_DISPLAY, null, -1,
+ new IScrollCaptureController.Stub() {
+ @Override
+ public void onClientConnected(
+ IScrollCaptureClient client, Rect scrollBounds,
+ Point positionInWindow) {
+ Log.d(TAG,
+ "client connected: " + client + "[scrollBounds= " + scrollBounds
+ + ", positionInWindow=" + positionInWindow + "]");
+ latch.countDown();
+ }
+
+ @Override
+ public void onClientUnavailable() {
+ }
+
+ @Override
+ public void onCaptureStarted() {
+ }
+
+ @Override
+ public void onCaptureBufferSent(long frameNumber, Rect capturedArea) {
+ }
+
+ @Override
+ public void onConnectionClosed() {
+ }
+ });
+ } catch (RemoteException e) {
+ Log.e(TAG, "request failed", e);
+ fail("caught remote exception " + e);
+ }
+ latch.await(1000, TimeUnit.MILLISECONDS);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollViewActivity.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollViewActivity.java
new file mode 100644
index 000000000000..bd3725942eca
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollViewActivity.java
@@ -0,0 +1,42 @@
+/*
+ * 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.screenshot;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.TypedValue;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+public class ScrollViewActivity extends Activity {
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ScrollView scrollView = new ScrollView(this);
+ LinearLayout linearLayout = new LinearLayout(this);
+ linearLayout.setOrientation(LinearLayout.VERTICAL);
+ TextView text = new TextView(this);
+ text.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 40);
+ text.setText(com.android.systemui.R.string.test_content);
+ linearLayout.addView(text);
+ scrollView.addView(linearLayout);
+ setContentView(scrollView);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 1259d28c3400..d2bf483a6bd6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
@@ -219,7 +218,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
mViewHierarchyManager.onDynamicPrivacyChanged();
}
return null;
- }).when(mListContainer).setMaxDisplayedNotifications(anyInt());
+ }).when(mListContainer).onNotificationViewUpdateFinished();
// WHEN we call updateNotificationViews()
mViewHierarchyManager.updateNotificationViews();
@@ -247,7 +246,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
mViewHierarchyManager.onDynamicPrivacyChanged();
}
return null;
- }).when(mListContainer).setMaxDisplayedNotifications(anyInt());
+ }).when(mListContainer).onNotificationViewUpdateFinished();
// WHEN we call updateNotificationViews() and drain the looper
mViewHierarchyManager.updateNotificationViews();
@@ -262,7 +261,6 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
private class FakeListContainer implements NotificationListContainer {
final LinearLayout mLayout = new LinearLayout(mContext);
final List<View> mRows = Lists.newArrayList();
- private boolean mMakeReentrantCallDuringSetMaxDisplayedNotifications;
@Override
public void setChildTransferInProgress(boolean childTransferInProgress) {}
@@ -322,9 +320,6 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
@Override
public void setMaxDisplayedNotifications(int maxNotifications) {
- if (mMakeReentrantCallDuringSetMaxDisplayedNotifications) {
- mViewHierarchyManager.onDynamicPrivacyChanged();
- }
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index d4718e7e55fa..fc0201ad82f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -346,7 +346,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
setSmartActions(mEntry.getKey(), null);
mEntryManager.updateNotificationRanking(mRankingMap);
- verify(mRow, never()).setEntry(eq(mEntry));
assertNull(mEntry.getSmartActions());
}
@@ -360,7 +359,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
setSmartActions(mEntry.getKey(), new ArrayList<>(Arrays.asList(createAction())));
mEntryManager.updateNotificationRanking(mRankingMap);
- verify(mRow, never()).setEntry(eq(mEntry));
assertEquals(1, mEntry.getSmartActions().size());
assertEquals("action", mEntry.getSmartActions().get(0).title);
}
@@ -375,7 +373,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
setSmartActions(mEntry.getKey(), new ArrayList<>(Arrays.asList(createAction())));
mEntryManager.updateNotificationRanking(mRankingMap);
- verify(mRow, never()).setEntry(eq(mEntry));
assertEquals(1, mEntry.getSmartActions().size());
assertEquals("action", mEntry.getSmartActions().get(0).title);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index 1523653dec3c..3dc29a1ae4d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -53,7 +53,6 @@ public class NotificationEntryBuilder {
/* ListEntry properties */
private GroupEntry mParent;
- private int mSection = -1;
/* If set, use this creation time instead of mClock.uptimeMillis */
private long mCreationTime = -1;
@@ -68,7 +67,6 @@ public class NotificationEntryBuilder {
mRankingBuilder = new RankingBuilder(source.getRanking());
mParent = source.getParent();
- mSection = source.getSection();
mCreationTime = source.getCreationTime();
}
@@ -104,7 +102,6 @@ public class NotificationEntryBuilder {
/* ListEntry properties */
entry.setParent(mParent);
- entry.getAttachState().setSectionIndex(mSection);
return entry;
}
@@ -117,14 +114,6 @@ public class NotificationEntryBuilder {
}
/**
- * Sets the section.
- */
- public NotificationEntryBuilder setSection(int section) {
- mSection = section;
- return this;
- }
-
- /**
* Sets the SBN directly. If set, causes all calls to delegated SbnBuilder methods to be
* ignored.
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 6fa5055c875d..8acb705c744d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -35,6 +35,8 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static java.util.Collections.singletonList;
+
import android.os.SystemClock;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -46,6 +48,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.NotificationInteractionTracker;
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder.OnRenderListListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
@@ -54,7 +57,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.ShadeL
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
import com.android.systemui.util.time.FakeSystemClock;
@@ -71,7 +74,6 @@ import org.mockito.Spy;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -496,7 +498,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
assertTrue(entry.hasFinishedInitialization());
// WHEN the pipeline is kicked off
- mReadyForBuildListener.onBuildList(Arrays.asList(entry));
+ mReadyForBuildListener.onBuildList(singletonList(entry));
// THEN the entry's initialization time is reset
assertFalse(entry.hasFinishedInitialization());
@@ -609,13 +611,18 @@ public class ShadeListBuilderTest extends SysuiTestCase {
// GIVEN a filter that removes all PACKAGE_4 notifs and sections that divide
// notifs based on package name
mListBuilder.addPreGroupFilter(new PackageFilter(PACKAGE_4));
- final NotifSection pkg1Section = spy(new PackageSection(PACKAGE_1));
- final NotifSection pkg2Section = spy(new PackageSection(PACKAGE_2));
+ final NotifSectioner pkg1Sectioner = spy(new PackageSectioner(PACKAGE_1));
+ final NotifSectioner pkg2Sectioner = spy(new PackageSectioner(PACKAGE_2));
// NOTE: no package 3 section explicitly added, so notifs with package 3 will get set by
// ShadeListBuilder's sDefaultSection which will demote it to the last section
- final NotifSection pkg4Section = spy(new PackageSection(PACKAGE_4));
- final NotifSection pkg5Section = spy(new PackageSection(PACKAGE_5));
- mListBuilder.setSections(Arrays.asList(pkg1Section, pkg2Section, pkg4Section, pkg5Section));
+ final NotifSectioner pkg4Sectioner = spy(new PackageSectioner(PACKAGE_4));
+ final NotifSectioner pkg5Sectioner = spy(new PackageSectioner(PACKAGE_5));
+ mListBuilder.setSectioners(
+ Arrays.asList(pkg1Sectioner, pkg2Sectioner, pkg4Sectioner, pkg5Sectioner));
+
+ final NotifSection pkg1Section = new NotifSection(pkg1Sectioner, 0);
+ final NotifSection pkg2Section = new NotifSection(pkg2Sectioner, 1);
+ final NotifSection pkg5Section = new NotifSection(pkg5Sectioner, 3);
// WHEN we build a list with different packages
addNotif(0, PACKAGE_4);
@@ -648,72 +655,61 @@ public class ShadeListBuilderTest extends SysuiTestCase {
// THEN the first section (pkg1Section) is called on all top level elements (but
// no children and no entries that were filtered out)
- verify(pkg1Section).isInSection(mEntrySet.get(1));
- verify(pkg1Section).isInSection(mEntrySet.get(2));
- verify(pkg1Section).isInSection(mEntrySet.get(3));
- verify(pkg1Section).isInSection(mEntrySet.get(7));
- verify(pkg1Section).isInSection(mEntrySet.get(8));
- verify(pkg1Section).isInSection(mEntrySet.get(9));
- verify(pkg1Section).isInSection(mBuiltList.get(3));
-
- verify(pkg1Section, never()).isInSection(mEntrySet.get(0));
- verify(pkg1Section, never()).isInSection(mEntrySet.get(4));
- verify(pkg1Section, never()).isInSection(mEntrySet.get(5));
- verify(pkg1Section, never()).isInSection(mEntrySet.get(6));
- verify(pkg1Section, never()).isInSection(mEntrySet.get(10));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(1));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(2));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(3));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(7));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(8));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(9));
+ verify(pkg1Sectioner).isInSection(mBuiltList.get(3));
+
+ verify(pkg1Sectioner, never()).isInSection(mEntrySet.get(0));
+ verify(pkg1Sectioner, never()).isInSection(mEntrySet.get(4));
+ verify(pkg1Sectioner, never()).isInSection(mEntrySet.get(5));
+ verify(pkg1Sectioner, never()).isInSection(mEntrySet.get(6));
+ verify(pkg1Sectioner, never()).isInSection(mEntrySet.get(10));
// THEN the last section (pkg5Section) is not called on any of the entries that were
// filtered or already in a section
- verify(pkg5Section, never()).isInSection(mEntrySet.get(0));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(1));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(2));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(4));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(5));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(6));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(7));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(8));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(10));
-
- verify(pkg5Section).isInSection(mEntrySet.get(3));
- verify(pkg5Section).isInSection(mEntrySet.get(9));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(0));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(1));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(2));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(4));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(5));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(6));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(7));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(8));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(10));
+
+ verify(pkg5Sectioner).isInSection(mEntrySet.get(3));
+ verify(pkg5Sectioner).isInSection(mEntrySet.get(9));
// THEN the correct section is assigned for entries in pkg1Section
- assertEquals(pkg1Section, mEntrySet.get(2).getNotifSection());
- assertEquals(0, mEntrySet.get(2).getSection());
- assertEquals(pkg1Section, mEntrySet.get(7).getNotifSection());
- assertEquals(0, mEntrySet.get(7).getSection());
+ assertEquals(pkg1Section, mEntrySet.get(2).getSection());
+ assertEquals(pkg1Section, mEntrySet.get(7).getSection());
// THEN the correct section is assigned for entries in pkg2Section
- assertEquals(pkg2Section, mEntrySet.get(1).getNotifSection());
- assertEquals(1, mEntrySet.get(1).getSection());
- assertEquals(pkg2Section, mEntrySet.get(8).getNotifSection());
- assertEquals(1, mEntrySet.get(8).getSection());
- assertEquals(pkg2Section, mBuiltList.get(3).getNotifSection());
- assertEquals(1, mBuiltList.get(3).getSection());
+ assertEquals(pkg2Section, mEntrySet.get(1).getSection());
+ assertEquals(pkg2Section, mEntrySet.get(8).getSection());
+ assertEquals(pkg2Section, mBuiltList.get(3).getSection());
// THEN no section was assigned to entries in pkg4Section (since they were filtered)
- assertEquals(null, mEntrySet.get(0).getNotifSection());
- assertEquals(-1, mEntrySet.get(0).getSection());
- assertEquals(null, mEntrySet.get(10).getNotifSection());
- assertEquals(-1, mEntrySet.get(10).getSection());
-
+ assertNull(mEntrySet.get(0).getSection());
+ assertNull(mEntrySet.get(10).getSection());
// THEN the correct section is assigned for entries in pkg5Section
- assertEquals(pkg5Section, mEntrySet.get(9).getNotifSection());
- assertEquals(3, mEntrySet.get(9).getSection());
+ assertEquals(pkg5Section, mEntrySet.get(9).getSection());
// THEN the children entries are assigned the same section as its parent
- assertEquals(mBuiltList.get(3).getNotifSection(), child(5).entry.getNotifSection());
assertEquals(mBuiltList.get(3).getSection(), child(5).entry.getSection());
- assertEquals(mBuiltList.get(3).getNotifSection(), child(6).entry.getNotifSection());
assertEquals(mBuiltList.get(3).getSection(), child(6).entry.getSection());
}
@Test
public void testNotifUsesDefaultSection() {
// GIVEN a Section for Package2
- final NotifSection pkg2Section = spy(new PackageSection(PACKAGE_2));
- mListBuilder.setSections(Arrays.asList(pkg2Section));
+ final NotifSectioner pkg2Section = spy(new PackageSectioner(PACKAGE_2));
+ mListBuilder.setSectioners(singletonList(pkg2Section));
// WHEN we build a list with pkg1 and pkg2 packages
addNotif(0, PACKAGE_1);
@@ -727,8 +723,8 @@ public class ShadeListBuilderTest extends SysuiTestCase {
);
// THEN the entry that didn't have an explicit section gets assigned the DefaultSection
- assertEquals(1, notif(0).entry.getSection());
- assertNotNull(notif(0).entry.getNotifSection());
+ assertNotNull(notif(0).entry.getSection());
+ assertEquals(1, notif(0).entry.getSectionIndex());
}
@Test
@@ -763,15 +759,15 @@ public class ShadeListBuilderTest extends SysuiTestCase {
// GIVEN a bunch of registered listeners and pluggables
NotifFilter preGroupFilter = spy(new PackageFilter(PACKAGE_1));
NotifPromoter promoter = spy(new IdPromoter(3));
- NotifSection section = spy(new PackageSection(PACKAGE_1));
+ NotifSectioner section = spy(new PackageSectioner(PACKAGE_1));
NotifComparator comparator = spy(new HypeComparator(PACKAGE_4));
NotifFilter preRenderFilter = spy(new PackageFilter(PACKAGE_5));
mListBuilder.addPreGroupFilter(preGroupFilter);
mListBuilder.addOnBeforeTransformGroupsListener(mOnBeforeTransformGroupsListener);
mListBuilder.addPromoter(promoter);
mListBuilder.addOnBeforeSortListener(mOnBeforeSortListener);
- mListBuilder.setComparators(Collections.singletonList(comparator));
- mListBuilder.setSections(Arrays.asList(section));
+ mListBuilder.setComparators(singletonList(comparator));
+ mListBuilder.setSectioners(singletonList(section));
mListBuilder.addOnBeforeFinalizeFilterListener(mOnBeforeFinalizeFilterListener);
mListBuilder.addFinalizeFilter(preRenderFilter);
mListBuilder.addOnBeforeRenderListListener(mOnBeforeRenderListListener);
@@ -821,13 +817,13 @@ public class ShadeListBuilderTest extends SysuiTestCase {
// GIVEN a variety of pluggables
NotifFilter packageFilter = new PackageFilter(PACKAGE_1);
NotifPromoter idPromoter = new IdPromoter(4);
- NotifSection section = new PackageSection(PACKAGE_1);
+ NotifSectioner section = new PackageSectioner(PACKAGE_1);
NotifComparator hypeComparator = new HypeComparator(PACKAGE_2);
mListBuilder.addPreGroupFilter(packageFilter);
mListBuilder.addPromoter(idPromoter);
- mListBuilder.setSections(Arrays.asList(section));
- mListBuilder.setComparators(Collections.singletonList(hypeComparator));
+ mListBuilder.setSectioners(singletonList(section));
+ mListBuilder.setComparators(singletonList(hypeComparator));
// GIVEN a set of random notifs
addNotif(0, PACKAGE_1);
@@ -973,7 +969,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
RecordingOnBeforeSortListener listener =
new RecordingOnBeforeSortListener();
mListBuilder.addOnBeforeSortListener(listener);
- mListBuilder.setComparators(Arrays.asList(new HypeComparator(PACKAGE_3)));
+ mListBuilder.setComparators(singletonList(new HypeComparator(PACKAGE_3)));
// GIVEN some new notifs out of order
addNotif(0, PACKAGE_1);
@@ -1093,7 +1089,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
NotifComparator comparator = new HypeComparator(PACKAGE_5);
OnBeforeRenderListListener listener =
(list) -> comparator.invalidateList();
- mListBuilder.setComparators(Collections.singletonList(comparator));
+ mListBuilder.setComparators(singletonList(comparator));
mListBuilder.addOnBeforeRenderListListener(listener);
// WHEN we try to run the pipeline and the comparator is invalidated
@@ -1420,10 +1416,10 @@ public class ShadeListBuilderTest extends SysuiTestCase {
}
/** Represents a section for the passed pkg */
- private static class PackageSection extends NotifSection {
+ private static class PackageSectioner extends NotifSectioner {
private final String mPackage;
- PackageSection(String pkg) {
+ PackageSectioner(String pkg) {
super("PackageSection_" + pkg);
mPackage = pkg;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
index ce8ce2e39bcc..639e791cbf23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
@@ -21,11 +21,9 @@ import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_MIN;
-import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -37,7 +35,6 @@ import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.util.ArraySet;
import androidx.test.filters.SmallTest;
@@ -48,8 +45,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -61,8 +57,6 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.List;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -78,7 +72,7 @@ public class AppOpsCoordinatorTest extends SysuiTestCase {
private AppOpsCoordinator mAppOpsCoordinator;
private NotifFilter mForegroundFilter;
private NotifLifetimeExtender mForegroundNotifLifetimeExtender;
- private NotifSection mFgsSection;
+ private NotifSectioner mFgsSection;
private FakeSystemClock mClock = new FakeSystemClock();
private FakeExecutor mExecutor = new FakeExecutor(mClock);
@@ -111,7 +105,7 @@ public class AppOpsCoordinatorTest extends SysuiTestCase {
lifetimeExtenderCaptor.capture());
mForegroundNotifLifetimeExtender = lifetimeExtenderCaptor.getValue();
- mFgsSection = mAppOpsCoordinator.getSection();
+ mFgsSection = mAppOpsCoordinator.getSectioner();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
index be5c8a846afb..c49393d2ed34 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
@@ -25,7 +25,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
import org.junit.Assert.assertFalse
@@ -45,7 +45,7 @@ import org.mockito.Mockito.`when` as whenever
class ConversationCoordinatorTest : SysuiTestCase() {
// captured listeners and pluggables:
private lateinit var promoter: NotifPromoter
- private lateinit var peopleSection: NotifSection
+ private lateinit var peopleSectioner: NotifSectioner
@Mock
private lateinit var pipeline: NotifPipeline
@@ -70,7 +70,7 @@ class ConversationCoordinatorTest : SysuiTestCase() {
verify(pipeline).addPromoter(notifPromoterCaptor.capture())
promoter = notifPromoterCaptor.value
- peopleSection = coordinator.getSection()
+ peopleSectioner = coordinator.sectioner
entry = NotificationEntryBuilder().setChannel(channel).build()
}
@@ -88,7 +88,7 @@ class ConversationCoordinatorTest : SysuiTestCase() {
entry.sbn, entry.ranking)).thenReturn(TYPE_PERSON)
// only put people notifications in this section
- assertTrue(peopleSection.isInSection(entry))
- assertFalse(peopleSection.isInSection(NotificationEntryBuilder().build()))
+ assertTrue(peopleSectioner.isInSection(entry))
+ assertFalse(peopleSectioner.isInSection(NotificationEntryBuilder().build()))
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
index 730481afe638..fa992a5d5dbb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
@@ -36,7 +36,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder;
@@ -64,7 +64,7 @@ public class HeadsUpCoordinatorTest extends SysuiTestCase {
private NotifPromoter mNotifPromoter;
private NotifLifetimeExtender mNotifLifetimeExtender;
private OnHeadsUpChangedListener mOnHeadsUpChangedListener;
- private NotifSection mNotifSection;
+ private NotifSectioner mNotifSectioner;
@Mock private NotifPipeline mNotifPipeline;
@Mock private HeadsUpManager mHeadsUpManager;
@@ -111,7 +111,7 @@ public class HeadsUpCoordinatorTest extends SysuiTestCase {
mNotifLifetimeExtender = notifLifetimeExtenderCaptor.getValue();
mOnHeadsUpChangedListener = headsUpChangedListenerCaptor.getValue();
- mNotifSection = mCoordinator.getSection();
+ mNotifSectioner = mCoordinator.getSectioner();
mNotifLifetimeExtender.setCallback(mEndLifetimeExtension);
mEntry = new NotificationEntryBuilder().build();
}
@@ -132,8 +132,8 @@ public class HeadsUpCoordinatorTest extends SysuiTestCase {
setCurrentHUN(mEntry);
// THEN only section the current HUN, mEntry
- assertTrue(mNotifSection.isInSection(mEntry));
- assertFalse(mNotifSection.isInSection(new NotificationEntryBuilder().build()));
+ assertTrue(mNotifSectioner.isInSection(mEntry));
+ assertFalse(mNotifSectioner.isInSection(new NotificationEntryBuilder().build()));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
index 5f10f38b2ee8..3a7d28ab56ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
@@ -36,7 +36,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import org.junit.Before;
@@ -61,8 +61,8 @@ public class RankingCoordinatorTest extends SysuiTestCase {
private NotifFilter mCapturedSuspendedFilter;
private NotifFilter mCapturedDozingFilter;
- private NotifSection mAlertingSection;
- private NotifSection mSilentSection;
+ private NotifSectioner mAlertingSectioner;
+ private NotifSectioner mSilentSectioner;
@Before
public void setup() {
@@ -76,8 +76,8 @@ public class RankingCoordinatorTest extends SysuiTestCase {
mCapturedSuspendedFilter = mNotifFilterCaptor.getAllValues().get(0);
mCapturedDozingFilter = mNotifFilterCaptor.getAllValues().get(1);
- mAlertingSection = rankingCoordinator.getAlertingSection();
- mSilentSection = rankingCoordinator.getSilentSection();
+ mAlertingSectioner = rankingCoordinator.getAlertingSectioner();
+ mSilentSectioner = rankingCoordinator.getSilentSectioner();
}
@Test
@@ -146,8 +146,8 @@ public class RankingCoordinatorTest extends SysuiTestCase {
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
// THEN entry is in the alerting section
- assertTrue(mAlertingSection.isInSection(mEntry));
- assertFalse(mSilentSection.isInSection(mEntry));
+ assertTrue(mAlertingSectioner.isInSection(mEntry));
+ assertFalse(mSilentSectioner.isInSection(mEntry));
}
@Test
@@ -156,8 +156,8 @@ public class RankingCoordinatorTest extends SysuiTestCase {
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
// THEN entry is in the silent section
- assertFalse(mAlertingSection.isInSection(mEntry));
- assertTrue(mSilentSection.isInSection(mEntry));
+ assertFalse(mAlertingSectioner.isInSection(mEntry));
+ assertTrue(mSilentSectioner.isInSection(mEntry));
}
private RankingBuilder getRankingForUnfilteredNotif() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 9a8678f01870..df26c5b15505 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -406,12 +406,12 @@ public class NotificationTestHelper {
entry.setRow(row);
mIconManager.createIcons(entry);
- row.setEntry(entry);
mBindPipelineEntryListener.onEntryInit(entry);
mBindPipeline.manageRow(entry, row);
row.initialize(
+ entry,
APP_NAME,
entry.getKey(),
mock(ExpansionLogger.class),
@@ -426,6 +426,7 @@ public class NotificationTestHelper {
mStatusBarStateController,
mPeopleNotificationIdentifier,
mock(OnUserInteractionCallback.class));
+
row.setAboveShelfChangedListener(aboveShelf -> { });
mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
inflateAndWait(entry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 9a6674e165e4..fa9ea6b1ea10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -18,15 +18,12 @@ import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MOD
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
@@ -36,30 +33,25 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.metrics.LogMaker;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.view.View;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -87,14 +79,13 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.KeyguardBypassEnabledProvider;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.leak.LeakDetector;
import org.junit.After;
@@ -103,7 +94,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -135,14 +125,12 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Mock private NotificationIconAreaController mNotificationIconAreaController;
@Mock private MetricsLogger mMetricsLogger;
@Mock private NotificationRoundnessManager mNotificationRoundnessManager;
- @Mock private KeyguardBypassController mKeyguardBypassController;
- @Mock private KeyguardMediaController mKeyguardMediaController;
- @Mock private ZenModeController mZenModeController;
+ @Mock private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider;
@Mock private NotificationSectionsManager mNotificationSectionsManager;
@Mock private NotificationSection mNotificationSection;
- @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private FeatureFlags mFeatureFlags;
- private UserChangedListener mUserChangedListener;
+ @Mock private SysuiStatusBarStateController mStatusBarStateController;
+ @Mock private NotificationSwipeHelper mNotificationSwipeHelper;
private NotificationEntryManager mEntryManager;
private int mOriginalInterruptionModelSetting;
private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
@@ -172,8 +160,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mDependency.injectMockDependency(ShadeController.class);
when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
- ArgumentCaptor<UserChangedListener> userChangedCaptor = ArgumentCaptor
- .forClass(UserChangedListener.class);
mEntryManager = new NotificationEntryManager(
mock(NotificationEntryManagerLogger.class),
mock(NotificationGroupManager.class),
@@ -211,17 +197,15 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
// which refer to members of NotificationStackScrollLayout. The spy
// holds a copy of the CUT's instances of these KeyguardBypassController, so they still
// refer to the CUT's member variables, not the spy's member variables.
- mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null,
+ mStackScrollerInternal = new NotificationStackScrollLayout(
+ getContext(),
+ null,
mNotificationRoundnessManager,
mock(DynamicPrivacyController.class),
- mock(SysuiStatusBarStateController.class),
+ mStatusBarStateController,
mHeadsUpManager,
- mKeyguardBypassController,
- mKeyguardMediaController,
new FalsingManagerFake(),
- mLockscreenUserManager,
mock(NotificationGutsManager.class),
- mZenModeController,
mNotificationSectionsManager,
mock(ForegroundServiceSectionController.class),
mock(ForegroundServiceDismissalFeatureController.class),
@@ -231,8 +215,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mock(NotifCollection.class),
mUiEventLoggerFake
);
- verify(mLockscreenUserManager).addUserChangedListener(userChangedCaptor.capture());
- mUserChangedListener = userChangedCaptor.getValue();
+ mStackScrollerInternal.initView(getContext(), mKeyguardBypassEnabledProvider,
+ mNotificationSwipeHelper);
mStackScroller = spy(mStackScrollerInternal);
mStackScroller.setShelfController(notificationShelfController);
mStackScroller.setStatusBar(mBar);
@@ -269,9 +253,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
public void updateEmptyView_dndSuppressing() {
when(mEmptyShadeView.willBeGone()).thenReturn(true);
- when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true);
- mStackScroller.updateEmptyShadeView(true);
+ mStackScroller.updateEmptyShadeView(true, true);
verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
}
@@ -280,9 +263,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
public void updateEmptyView_dndNotSuppressing() {
mStackScroller.setEmptyShadeView(mEmptyShadeView);
when(mEmptyShadeView.willBeGone()).thenReturn(true);
- when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
- mStackScroller.updateEmptyShadeView(true);
+ mStackScroller.updateEmptyShadeView(true, false);
verify(mEmptyShadeView).setText(R.string.empty_shade_text);
}
@@ -291,12 +273,10 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
public void updateEmptyView_noNotificationsToDndSuppressing() {
mStackScroller.setEmptyShadeView(mEmptyShadeView);
when(mEmptyShadeView.willBeGone()).thenReturn(true);
- when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
- mStackScroller.updateEmptyShadeView(true);
+ mStackScroller.updateEmptyShadeView(true, false);
verify(mEmptyShadeView).setText(R.string.empty_shade_text);
- when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true);
- mStackScroller.updateEmptyShadeView(true);
+ mStackScroller.updateEmptyShadeView(true, true);
verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
}
@@ -312,12 +292,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
}
@Test
- public void testOnStatePostChange_verifyIfProfileIsPublic() {
- mUserChangedListener.onUserChanged(0);
- verify(mLockscreenUserManager).isAnyProfilePublicMode();
- }
-
- @Test
public void manageNotifications_visible() {
FooterView view = mock(FooterView.class);
mStackScroller.setFooterView(view);
@@ -446,86 +420,22 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
@UiThreadTest
public void testSetIsBeingDraggedResetsExposedMenu() {
- NotificationSwipeHelper swipeActionHelper =
- (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
- swipeActionHelper.setExposedMenuView(new View(mContext));
mStackScroller.setIsBeingDragged(true);
- assertNull(swipeActionHelper.getExposedMenuView());
+ verify(mNotificationSwipeHelper).resetExposedMenuView(true, true);
}
@Test
@UiThreadTest
public void testPanelTrackingStartResetsExposedMenu() {
- NotificationSwipeHelper swipeActionHelper =
- (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
- swipeActionHelper.setExposedMenuView(new View(mContext));
mStackScroller.onPanelTrackingStarted();
- assertNull(swipeActionHelper.getExposedMenuView());
+ verify(mNotificationSwipeHelper).resetExposedMenuView(true, true);
}
@Test
@UiThreadTest
public void testDarkModeResetsExposedMenu() {
- NotificationSwipeHelper swipeActionHelper =
- (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
- swipeActionHelper.setExposedMenuView(new View(mContext));
mStackScroller.setHideAmount(0.1f, 0.1f);
- assertNull(swipeActionHelper.getExposedMenuView());
- }
-
- class LogMatcher implements ArgumentMatcher<LogMaker> {
- private int mCategory, mType;
-
- LogMatcher(int category, int type) {
- mCategory = category;
- mType = type;
- }
- public boolean matches(LogMaker l) {
- return (l.getCategory() == mCategory)
- && (l.getType() == mType);
- }
-
- public String toString() {
- return String.format("LogMaker(%d, %d)", mCategory, mType);
- }
- }
-
- private LogMaker logMatcher(int category, int type) {
- return argThat(new LogMatcher(category, type));
- }
-
- @Test
- @UiThreadTest
- public void testOnMenuClickedLogging() {
- // Set up the object under test to have a valid mLongPressListener. We're testing an
- // anonymous-class member, mMenuEventListener, so we need to modify the state of the
- // class itself, not the Mockito spy copied from it. See notes in setup.
- mStackScrollerInternal.setLongPressListener(
- mock(ExpandableNotificationRow.LongPressListener.class));
-
- ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
- when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
- MetricsProto.MetricsEvent.VIEW_UNKNOWN));
-
- mStackScroller.mMenuEventListener.onMenuClicked(row, 0, 0, mock(
- NotificationMenuRowPlugin.MenuItem.class));
- verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data
- verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_TOUCH_GEAR,
- MetricsProto.MetricsEvent.TYPE_ACTION));
- }
-
- @Test
- @UiThreadTest
- public void testOnMenuShownLogging() { ;
-
- ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
- when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
- MetricsProto.MetricsEvent.VIEW_UNKNOWN));
-
- mStackScroller.mMenuEventListener.onMenuShown(row);
- verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data
- verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_REVEAL_GEAR,
- MetricsProto.MetricsEvent.TYPE_ACTION));
+ verify(mNotificationSwipeHelper).resetExposedMenuView(true, true);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
index e3acf0213725..4fffd3e0124a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
@@ -17,25 +17,49 @@
package com.android.systemui.statusbar.notification.stack;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.res.Resources;
+import android.metrics.LogMaker;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.media.KeyguardMediaController;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -55,20 +79,46 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
@Mock
private TunerService mTunerService;
@Mock
- private AmbientState mAmbientState;
- @Mock
private DynamicPrivacyController mDynamicPrivacyController;
@Mock
private ConfigurationController mConfigurationController;
@Mock
private NotificationStackScrollLayout mNotificationStackScrollLayout;
+ @Mock
+ private ZenModeController mZenModeController;
+ @Mock
+ private KeyguardMediaController mKeyguardMediaController;
+ @Mock
+ private SysuiStatusBarStateController mSysuiStatusBarStateController;
+ @Mock
+ private KeyguardBypassController mKeyguardBypassController;
+ @Mock
+ private SysuiColorExtractor mColorExtractor;
+ @Mock
+ private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
+ @Mock
+ private MetricsLogger mMetricsLogger;
+ @Mock
+ private FalsingManager mFalsingManager;
+ @Mock
+ private NotificationSectionsManager mNotificationSectionsManager;
+ @Mock
+ private Resources mResources;
+ @Mock(answer = Answers.RETURNS_SELF)
+ private NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
+ @Mock
+ private NotificationSwipeHelper mNotificationSwipeHelper;
+ @Mock
+ private StatusBar mStatusBar;
- NotificationStackScrollLayoutController mController;
+ private NotificationStackScrollLayoutController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mNotificationSwipeHelperBuilder.build()).thenReturn(mNotificationSwipeHelper);
+
mController = new NotificationStackScrollLayoutController(
true,
mNotificationGutsManager,
@@ -76,7 +126,19 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
mNotificationRoundnessManager,
mTunerService,
mDynamicPrivacyController,
- mConfigurationController
+ mConfigurationController,
+ mSysuiStatusBarStateController,
+ mKeyguardMediaController,
+ mKeyguardBypassController,
+ mZenModeController,
+ mColorExtractor,
+ mNotificationLockscreenUserManager,
+ mMetricsLogger,
+ mFalsingManager,
+ mNotificationSectionsManager,
+ mResources,
+ mNotificationSwipeHelperBuilder,
+ mStatusBar
);
when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
@@ -112,4 +174,140 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
mController.mConfigurationListener.onDensityOrFontScaleChanged();
verify(mNotificationStackScrollLayout).reinflateViews();
}
+
+ @Test
+ public void testUpdateEmptyShadeView_notificationsVisible() {
+ when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true);
+ mController.attach(mNotificationStackScrollLayout);
+
+ mController.updateEmptyShadeView(true /* visible */);
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+ true /* visible */,
+ true /* notifVisibleInShade */);
+ reset(mNotificationStackScrollLayout);
+ mController.updateEmptyShadeView(false /* visible */);
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+ false /* visible */,
+ true /* notifVisibleInShade */);
+ }
+
+ @Test
+ public void testUpdateEmptyShadeView_notificationsHidden() {
+ when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
+ mController.attach(mNotificationStackScrollLayout);
+
+ mController.updateEmptyShadeView(true /* visible */);
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+ true /* visible */,
+ false /* notifVisibleInShade */);
+ reset(mNotificationStackScrollLayout);
+ mController.updateEmptyShadeView(false /* visible */);
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+ false /* visible */,
+ false /* notifVisibleInShade */);
+ }
+
+ @Test
+ public void testOnUserChange_verifySensitiveProfile() {
+ when(mNotificationLockscreenUserManager.isAnyProfilePublicMode()).thenReturn(true);
+
+ ArgumentCaptor<UserChangedListener> userChangedCaptor = ArgumentCaptor
+ .forClass(UserChangedListener.class);
+
+ mController.attach(mNotificationStackScrollLayout);
+ verify(mNotificationLockscreenUserManager)
+ .addUserChangedListener(userChangedCaptor.capture());
+ reset(mNotificationStackScrollLayout);
+
+ UserChangedListener changedListener = userChangedCaptor.getValue();
+ changedListener.onUserChanged(0);
+ verify(mNotificationStackScrollLayout).setCurrentUserid(0);
+ verify(mNotificationStackScrollLayout).updateSensitiveness(false, true);
+ }
+
+ @Test
+ public void testOnStatePostChange_verifyIfProfileIsPublic() {
+ when(mNotificationLockscreenUserManager.isAnyProfilePublicMode()).thenReturn(true);
+
+ ArgumentCaptor<StatusBarStateController.StateListener> stateListenerArgumentCaptor =
+ ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
+
+ mController.attach(mNotificationStackScrollLayout);
+ verify(mSysuiStatusBarStateController).addCallback(
+ stateListenerArgumentCaptor.capture(), anyInt());
+
+ StatusBarStateController.StateListener stateListener =
+ stateListenerArgumentCaptor.getValue();
+
+ stateListener.onStatePostChange();
+ verify(mNotificationStackScrollLayout).updateSensitiveness(false, true);
+ }
+
+
+ @Test
+ public void testOnMenuShownLogging() { ;
+
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
+ when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
+ MetricsProto.MetricsEvent.VIEW_UNKNOWN));
+
+
+ ArgumentCaptor<OnMenuEventListener> onMenuEventListenerArgumentCaptor =
+ ArgumentCaptor.forClass(OnMenuEventListener.class);
+
+ mController.attach(mNotificationStackScrollLayout);
+ verify(mNotificationSwipeHelperBuilder).setOnMenuEventListener(
+ onMenuEventListenerArgumentCaptor.capture());
+
+ OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue();
+
+ onMenuEventListener.onMenuShown(row);
+ verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data
+ verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_REVEAL_GEAR,
+ MetricsProto.MetricsEvent.TYPE_ACTION));
+ }
+
+ @Test
+ public void testOnMenuClickedLogging() {
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
+ when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
+ MetricsProto.MetricsEvent.VIEW_UNKNOWN));
+
+
+ ArgumentCaptor<OnMenuEventListener> onMenuEventListenerArgumentCaptor =
+ ArgumentCaptor.forClass(OnMenuEventListener.class);
+
+ mController.attach(mNotificationStackScrollLayout);
+ verify(mNotificationSwipeHelperBuilder).setOnMenuEventListener(
+ onMenuEventListenerArgumentCaptor.capture());
+
+ OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue();
+
+ onMenuEventListener.onMenuClicked(row, 0, 0, mock(
+ NotificationMenuRowPlugin.MenuItem.class));
+ verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data
+ verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_TOUCH_GEAR,
+ MetricsProto.MetricsEvent.TYPE_ACTION));
+ }
+
+ private LogMaker logMatcher(int category, int type) {
+ return argThat(new LogMatcher(category, type));
+ }
+
+ static class LogMatcher implements ArgumentMatcher<LogMaker> {
+ private int mCategory, mType;
+
+ LogMatcher(int category, int type) {
+ mCategory = category;
+ mType = type;
+ }
+ public boolean matches(LogMaker l) {
+ return (l.getCategory() == mCategory)
+ && (l.getType() == mType);
+ }
+
+ public String toString() {
+ return String.format("LogMaker(%d, %d)", mCategory, mType);
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index 323d8bd9d2e6..0faf5d478116 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -35,6 +35,7 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import androidx.test.filters.SmallTest;
@@ -78,7 +79,8 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
mCallback = mock(NotificationSwipeHelper.NotificationCallback.class);
mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class);
mSwipeHelper = spy(new NotificationSwipeHelper(
- SwipeHelper.X, mCallback, mContext, mListener, new FalsingManagerFake()));
+ mContext.getResources(), ViewConfiguration.get(mContext),
+ new FalsingManagerFake(), SwipeHelper.X, mCallback, mListener));
mView = mock(View.class);
mEvent = mock(MotionEvent.class);
mMenuRow = mock(NotificationMenuRowPlugin.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index c9e9d94d8a79..04e870d4b35c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -52,6 +52,7 @@ import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardClockSwitch;
import com.android.keyguard.KeyguardClockSwitchController;
+import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -217,6 +218,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
when(mKeyguardBottomArea.getRightView()).thenReturn(mock(KeyguardAffordanceView.class));
when(mView.findViewById(R.id.big_clock_container)).thenReturn(mBigClockContainer);
when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
+ when(mView.findViewById(R.id.keyguard_status_view))
+ .thenReturn(mock(KeyguardStatusView.class));
FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder(
mDisplayMetrics);
@@ -239,6 +242,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mStatusBarStateController,
new FalsingManagerFake());
mNotificationPanelViewController = new NotificationPanelViewController(mView,
+ mResources,
mInjectionInflationController,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
mFalsingManager, mShadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index ccc307841491..2f4511329041 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -43,6 +43,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.FalsingManager;
@@ -58,6 +59,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Optional;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -89,6 +92,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
private View mNotificationContainer;
@Mock
private KeyguardBypassController mBypassController;
+ @Mock
+ private FaceAuthScreenBrightnessController mFaceAuthScreenBrightnessController;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Before
@@ -108,6 +113,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mock(DockManager.class),
mock(NotificationShadeWindowController.class),
mKeyguardStateController,
+ mFaceAuthScreenBrightnessController,
mock(NotificationMediaManager.class));
mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar, mContainer,
mNotificationPanelView, mBiometrucUnlockController, mDismissCallbackRegistry,
@@ -274,11 +280,12 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
DockManager dockManager,
NotificationShadeWindowController notificationShadeWindowController,
KeyguardStateController keyguardStateController,
+ FaceAuthScreenBrightnessController faceAuthScreenBrightnessController,
NotificationMediaManager notificationMediaManager) {
super(context, callback, lockPatternUtils, sysuiStatusBarStateController,
configurationController, keyguardUpdateMonitor, navigationModeController,
dockManager, notificationShadeWindowController, keyguardStateController,
- notificationMediaManager);
+ Optional.of(faceAuthScreenBrightnessController), notificationMediaManager);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 8462386aaf2d..87aee3fd4794 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -96,7 +96,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationListener;
@@ -238,7 +238,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private StatusBarComponent.Builder mStatusBarComponentBuilder;
@Mock private StatusBarComponent mStatusBarComponent;
@Mock private PluginManager mPluginManager;
- @Mock private Divider mDivider;
+ @Mock private SplitScreen mSplitScreen;
@Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
@Mock private LightsOutNotifController mLightsOutNotifController;
@Mock private ViewMediatorCallback mViewMediatorCallback;
@@ -397,7 +397,7 @@ public class StatusBarTest extends SysuiTestCase {
Optional.of(mRecents),
mStatusBarComponentBuilderProvider,
mPluginManager,
- Optional.of(mDivider),
+ Optional.of(mSplitScreen),
mLightsOutNotifController,
mStatusBarNotificationActivityStarterBuilder,
mShadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index fbbfa9611217..3dd36d134cf7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -41,6 +41,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
import org.junit.Before;
import org.junit.Test;
@@ -58,6 +59,7 @@ public class BluetoothControllerImplTest extends SysuiTestCase {
private CachedBluetoothDeviceManager mMockDeviceManager;
private LocalBluetoothAdapter mMockAdapter;
private TestableLooper mTestableLooper;
+ private DumpManager mMockDumpManager;
private BluetoothControllerImpl mBluetoothControllerImpl;
private List<CachedBluetoothDevice> mDevices;
@@ -75,8 +77,10 @@ public class BluetoothControllerImplTest extends SysuiTestCase {
when(mMockBluetoothManager.getEventManager()).thenReturn(mock(BluetoothEventManager.class));
when(mMockBluetoothManager.getProfileManager())
.thenReturn(mock(LocalBluetoothProfileManager.class));
+ mMockDumpManager = mock(DumpManager.class);
mBluetoothControllerImpl = new BluetoothControllerImpl(mContext,
+ mMockDumpManager,
mTestableLooper.getLooper(),
mTestableLooper.getLooper(),
mMockBluetoothManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
index 260ff2dafeed..33ece0084906 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
@@ -70,9 +70,7 @@ public class DeviceConfigProxyFake extends DeviceConfigProxy {
for (Pair<Executor, OnPropertiesChangedListener> listener : mListeners) {
Properties.Builder propBuilder = new Properties.Builder(namespace);
- for (String key : mProperties.get(namespace).keySet()) {
- propBuilder.setString(key, mProperties.get(namespace).get(key));
- }
+ propBuilder.setString(name, value);
listener.first.execute(() -> listener.second.onPropertiesChanged(propBuilder.build()));
}
return true;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFakeTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFakeTest.java
new file mode 100644
index 000000000000..64e89579393e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFakeTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.util;
+
+import static android.provider.DeviceConfig.Properties;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.provider.DeviceConfig.OnPropertiesChangedListener;
+
+import androidx.annotation.NonNull;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DeviceConfigProxyFakeTest extends SysuiTestCase {
+ private static final String NAMESPACE = "foobar";
+
+ private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+
+ private DeviceConfigProxyFake mDeviceConfigProxyFake;
+
+ @Before
+ public void setup() {
+ mDeviceConfigProxyFake = new DeviceConfigProxyFake();
+ }
+
+ @Test
+ public void testOnPropertiesChanged() {
+ TestableListener onPropertiesChangedListener = new TestableListener();
+ String key = "foo";
+ String value = "bar";
+
+ mDeviceConfigProxyFake.addOnPropertiesChangedListener(
+ NAMESPACE, mFakeExecutor, onPropertiesChangedListener);
+
+ mDeviceConfigProxyFake.setProperty(NAMESPACE, key, value, false);
+ mFakeExecutor.runAllReady();
+ assertThat(onPropertiesChangedListener.mProperties).isNotNull();
+ assertThat(onPropertiesChangedListener.mProperties.getKeyset().size()).isEqualTo(1);
+ assertThat(onPropertiesChangedListener.mProperties.getString(key, "")).isEqualTo(value);
+ }
+
+ @Test
+ public void testOnMultiplePropertiesChanged() {
+ TestableListener onPropertiesChangedListener = new TestableListener();
+ String keyA = "foo";
+ String valueA = "bar";
+ String keyB = "bada";
+ String valueB = "boom";
+
+ mDeviceConfigProxyFake.addOnPropertiesChangedListener(
+ NAMESPACE, mFakeExecutor, onPropertiesChangedListener);
+ mDeviceConfigProxyFake.setProperty(NAMESPACE, keyA, valueA, false);
+ mFakeExecutor.runAllReady();
+ assertThat(onPropertiesChangedListener.mProperties).isNotNull();
+ assertThat(onPropertiesChangedListener.mProperties.getKeyset().size()).isEqualTo(1);
+ assertThat(onPropertiesChangedListener.mProperties.getString(keyA, "")).isEqualTo(valueA);
+
+ mDeviceConfigProxyFake.setProperty(NAMESPACE, keyB, valueB, false);
+ mFakeExecutor.runAllReady();
+ assertThat(onPropertiesChangedListener.mProperties).isNotNull();
+ assertThat(onPropertiesChangedListener.mProperties.getKeyset().size()).isEqualTo(1);
+ assertThat(onPropertiesChangedListener.mProperties.getString(keyB, "")).isEqualTo(valueB);
+ }
+
+ private static class TestableListener implements OnPropertiesChangedListener {
+ Properties mProperties;
+
+ TestableListener() {
+ }
+ @Override
+ public void onPropertiesChanged(@NonNull Properties properties) {
+ mProperties = properties;
+ }
+ }
+}
diff --git a/services/Android.bp b/services/Android.bp
index b348b91a1bd7..ef52c2aff002 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -156,10 +156,14 @@ droidstubs {
java_library {
name: "android_system_server_stubs_current",
+ defaults: ["android_stubs_dists_default"],
srcs: [":services-stubs.sources"],
installable: false,
static_libs: ["android_module_lib_stubs_current"],
sdk_version: "none",
system_modules: "none",
java_version: "1.8",
+ dist: {
+ dir: "apistubs/android/system-server",
+ },
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 669bb24e0e77..a75b64ce08f5 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -284,11 +284,13 @@ public class AccessibilityWindowManager {
* Computes partial interactive region of given windowId.
*
* @param windowId The windowId
+ * @param forceComputeRegion set outRegion when the windowId matches one on the screen even
+ * though the region is not covered by other windows above it.
* @param outRegion The output to which to write the bounds.
- * @return true if outRegion is not empty.
+ * @return {@code true} if outRegion is not empty.
*/
boolean computePartialInteractiveRegionForWindowLocked(int windowId,
- @NonNull Region outRegion) {
+ boolean forceComputeRegion, @NonNull Region outRegion) {
if (mWindows == null) {
return false;
}
@@ -309,6 +311,9 @@ public class AccessibilityWindowManager {
currentWindow.getRegionInScreen(currentWindowRegions);
outRegion.set(currentWindowRegions);
windowInteractiveRegion = outRegion;
+ if (forceComputeRegion) {
+ windowInteractiveRegionChanged = true;
+ }
continue;
}
} else if (currentWindow.getType()
@@ -1240,10 +1245,13 @@ public class AccessibilityWindowManager {
*/
public boolean computePartialInteractiveRegionForWindowLocked(int windowId,
@NonNull Region outRegion) {
- windowId = resolveParentWindowIdLocked(windowId);
- final DisplayWindowsObserver observer = getDisplayWindowObserverByWindowIdLocked(windowId);
+ final int parentWindowId = resolveParentWindowIdLocked(windowId);
+ final DisplayWindowsObserver observer = getDisplayWindowObserverByWindowIdLocked(
+ parentWindowId);
+
if (observer != null) {
- return observer.computePartialInteractiveRegionForWindowLocked(windowId, outRegion);
+ return observer.computePartialInteractiveRegionForWindowLocked(parentWindowId,
+ parentWindowId != windowId, outRegion);
}
return false;
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index a2d58c8019fc..b587dd33c4e5 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -561,24 +561,6 @@ public class TouchExplorer extends BaseEventStreamTransformation
// stream consistent.
sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
- if (mGestureDetector.isMultiFingerGesturesEnabled()
- && mGestureDetector.isTwoFingerPassthroughEnabled()) {
- if (event.getPointerCount() == 3) {
- boolean isOnBottomEdge = false;
- // If three fingers go down on the bottom edge of the screen, delegate immediately.
- final long screenHeight = mContext.getResources().getDisplayMetrics().heightPixels;
- for (int i = 0; i < TouchState.MAX_POINTER_COUNT; ++i) {
- if (mReceivedPointerTracker.getReceivedPointerDownY(i)
- > (screenHeight - mEdgeSwipeHeightPixels)) {
- isOnBottomEdge = true;
- }
- }
- if (isOnBottomEdge) {
- mState.startDelegating();
- mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
- }
- }
- }
}
/**
@@ -644,12 +626,34 @@ public class TouchExplorer extends BaseEventStreamTransformation
break;
default:
if (mGestureDetector.isMultiFingerGesturesEnabled()) {
- return;
+ if (mGestureDetector.isTwoFingerPassthroughEnabled()) {
+ if (event.getPointerCount() == 3) {
+ boolean isOnBottomEdge = true;
+ // If three fingers went down on the bottom edge of the screen, delegate
+ // immediately.
+ final long screenHeight =
+ mContext.getResources().getDisplayMetrics().heightPixels;
+ for (int i = 0; i < TouchState.MAX_POINTER_COUNT; ++i) {
+ if (mReceivedPointerTracker.getReceivedPointerDownY(i)
+ < (screenHeight - mEdgeSwipeHeightPixels)) {
+ isOnBottomEdge = false;
+ }
+ }
+ if (isOnBottomEdge) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "Three-finger edge swipe detected.");
+ }
+ mState.startDelegating();
+ mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
+ }
+ }
+ }
+ } else {
+ // More than two pointers are delegated to the view hierarchy.
+ mState.startDelegating();
+ event = MotionEvent.obtainNoHistory(event);
+ mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
}
- // More than two pointers are delegated to the view hierarchy.
- mState.startDelegating();
- event = MotionEvent.obtainNoHistory(event);
- mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
break;
}
}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index ad1986a6669f..cf9324c13ae8 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -302,24 +302,11 @@ public abstract class PackageManagerInternal {
String packageName, int userId);
/**
- * Do a straight uid lookup for the given package/application in the given user. This enforces
- * app visibility rules and permissions. Call {@link #getPackageUidInternal} for the internal
- * implementation.
- * @deprecated Use {@link PackageManager#getPackageUid(String, int)}
- * @return The app's uid, or < 0 if the package was not found in that user
- */
- @Deprecated
- public abstract int getPackageUid(String packageName,
- @PackageInfoFlags int flags, int userId);
-
- /**
* Do a straight uid lookup for the given package/application in the given user.
* @see PackageManager#getPackageUidAsUser(String, int, int)
* @return The app's uid, or < 0 if the package was not found in that user
- * TODO(b/148235092): rename this to getPackageUid
*/
- public abstract int getPackageUidInternal(String packageName,
- @PackageInfoFlags int flags, int userId);
+ public abstract int getPackageUid(String packageName, @PackageInfoFlags int flags, int userId);
/**
* Retrieve all of the information we know about a particular package/application.
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index b72985cc8f2c..27c5d4a53956 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2160,7 +2160,7 @@ class StorageManagerService extends IStorageManager.Stub
Slog.i(TAG, "Remounting storage for pid: " + pid);
final String[] sharedPackages =
mPmInternal.getSharedUserPackagesForPackage(packageName, userId);
- final int uid = mPmInternal.getPackageUidInternal(packageName, 0, userId);
+ final int uid = mPmInternal.getPackageUid(packageName, 0 /* flags */, userId);
final String[] packages =
sharedPackages.length != 0 ? sharedPackages : new String[]{packageName};
try {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 6d71c8e68f77..eb8308b56f2e 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -315,11 +315,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private List<Map<Pair<Integer, ApnSetting>, PreciseDataConnectionState>>
mPreciseDataConnectionStates;
- static final int ENFORCE_COARSE_LOCATION_PERMISSION_MASK =
- PhoneStateListener.LISTEN_REGISTRATION_FAILURE
- | PhoneStateListener.LISTEN_BARRING_INFO;
-
- static final int ENFORCE_FINE_LOCATION_PERMISSION_MASK =
+ // Starting in Q, almost all cellular location requires FINE location enforcement.
+ // Prior to Q, cellular was available with COARSE location enforcement. Bits in this
+ // list will be checked for COARSE on apps targeting P or earlier and FINE on Q or later.
+ static final int ENFORCE_LOCATION_PERMISSION_MASK =
PhoneStateListener.LISTEN_CELL_LOCATION
| PhoneStateListener.LISTEN_CELL_INFO
| PhoneStateListener.LISTEN_REGISTRATION_FAILURE
@@ -376,7 +375,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
+ " newDefaultPhoneId=" + newDefaultPhoneId);
}
- //Due to possible risk condition,(notify call back using the new
+ //Due to possible race condition,(notify call back using the new
//defaultSubId comes before new defaultSubId update) we need to recall all
//possible missed notify callback
synchronized (mRecords) {
@@ -909,7 +908,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
try {
if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]);
- if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
// null will be translated to empty CellLocation object in client.
r.callback.onCellLocationChanged(mCellIdentity[phoneId]);
}
@@ -964,7 +964,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
- if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
}
} catch (RemoteException ex) {
@@ -1518,7 +1519,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) &&
idMatch(r.subId, subId, phoneId) &&
- checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
try {
if (DBG_LOC) {
log("notifyCellInfoForSubscriber: mCellInfo=" + cellInfo
@@ -1797,7 +1799,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
idMatch(r.subId, subId, phoneId) &&
- checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
try {
if (DBG_LOC) {
log("notifyCellLocation: cellLocation=" + cellLocation
@@ -2103,20 +2106,20 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
mOutgoingCallEmergencyNumber[phoneId] = emergencyNumber;
- for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL)
- && idMatch(r.subId, subId, phoneId)) {
- try {
- r.callback.onOutgoingEmergencyCall(emergencyNumber);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
- }
+ }
+ for (Record r : mRecords) {
+ // Send to all listeners regardless of subscription
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL)) {
+ try {
+ r.callback.onOutgoingEmergencyCall(emergencyNumber, subId);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
}
}
}
- handleRemoveListLocked();
}
+ handleRemoveListLocked();
}
@Override
@@ -2544,16 +2547,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
boolean shouldCheckLocationPermissions = false;
- if ((events & ENFORCE_FINE_LOCATION_PERMISSION_MASK) != 0) {
+ if ((events & ENFORCE_LOCATION_PERMISSION_MASK) != 0) {
// Everything that requires fine location started in Q. So far...
locationQueryBuilder.setMinSdkVersionForFine(Build.VERSION_CODES.Q);
- // If we're enforcing fine starting in Q, we also want to enforce coarse starting in Q.
- locationQueryBuilder.setMinSdkVersionForCoarse(Build.VERSION_CODES.Q);
- locationQueryBuilder.setMinSdkVersionForEnforcement(Build.VERSION_CODES.Q);
- shouldCheckLocationPermissions = true;
- }
-
- if ((events & ENFORCE_COARSE_LOCATION_PERMISSION_MASK) != 0) {
+ // If we're enforcing fine starting in Q, we also want to enforce coarse even for
+ // older SDK versions.
locationQueryBuilder.setMinSdkVersionForCoarse(0);
locationQueryBuilder.setMinSdkVersionForEnforcement(0);
shouldCheckLocationPermissions = true;
@@ -2750,8 +2748,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if (VDBG) log("checkPossibleMissNotify: onServiceStateChanged state=" +
mServiceState[phoneId]);
- r.callback.onServiceStateChanged(
- new ServiceState(mServiceState[phoneId]));
+ ServiceState ss = new ServiceState(mServiceState[phoneId]);
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ r.callback.onServiceStateChanged(ss);
+ } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
+ r.callback.onServiceStateChanged(
+ ss.createLocationInfoSanitizedCopy(false));
+ } else {
+ r.callback.onServiceStateChanged(
+ ss.createLocationInfoSanitizedCopy(true));
+ }
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -2796,7 +2802,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
}
- if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
}
} catch (RemoteException ex) {
@@ -2862,7 +2869,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("checkPossibleMissNotify: onCellLocationChanged mCellIdentity = "
+ mCellIdentity[phoneId]);
}
- if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
// null will be translated to empty CellLocation object in client.
r.callback.onCellLocationChanged(mCellIdentity[phoneId]);
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 1815dac4c3a8..990a547144a0 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -99,6 +99,7 @@ public class Watchdog {
"android.hardware.audio@4.0::IDevicesFactory",
"android.hardware.audio@5.0::IDevicesFactory",
"android.hardware.audio@6.0::IDevicesFactory",
+ "android.hardware.audio@7.0::IDevicesFactory",
"android.hardware.biometrics.face@1.0::IBiometricsFace",
"android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint",
"android.hardware.bluetooth@1.0::IBluetoothHci",
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 6328cb60cf73..c31d73246ff6 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -453,16 +453,16 @@ public final class ActiveServices {
}
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
- int callingPid, int callingUid, boolean fgRequired, String callingPackage,
- @Nullable String callingFeatureId, final int userId)
+ int callingPid, int callingUid, boolean fgRequired, boolean hideFgNotification,
+ String callingPackage, @Nullable String callingFeatureId, final int userId)
throws TransactionTooLargeException {
return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
- callingPackage, callingFeatureId, userId, false);
+ hideFgNotification, callingPackage, callingFeatureId, userId, false);
}
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
- int callingPid, int callingUid, boolean fgRequired, String callingPackage,
- @Nullable String callingFeatureId, final int userId,
+ int callingPid, int callingUid, boolean fgRequired, boolean hideFgNotification,
+ String callingPackage, @Nullable String callingFeatureId, final int userId,
boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
@@ -626,6 +626,7 @@ public final class ActiveServices {
r.startRequested = true;
r.delayedStop = false;
r.fgRequired = fgRequired;
+ r.hideFgNotification = hideFgNotification;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants, callingUid));
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index e9539be8b0d5..fede1d2832b8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -89,6 +89,7 @@ final class ActivityManagerConstants extends ContentObserver {
static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
static final String KEY_PENDINGINTENT_WARNING_THRESHOLD = "pendingintent_warning_threshold";
+ static final String KEY_MIN_CRASH_INTERVAL = "min_crash_interval";
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -122,6 +123,8 @@ final class ActivityManagerConstants extends ContentObserver {
private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
private static final int DEFAULT_PENDINGINTENT_WARNING_THRESHOLD = 2000;
+ private static final int DEFAULT_MIN_CRASH_INTERVAL = 2 * 60 * 1000;
+
// Flag stored in the DeviceConfig API.
/**
@@ -281,6 +284,12 @@ final class ActivityManagerConstants extends ContentObserver {
// this long.
public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION;
+ /**
+ * The minimum time we allow between crashes, for us to consider this
+ * application to be bad and stop its services and reject broadcasts.
+ */
+ public static int MIN_CRASH_INTERVAL = DEFAULT_MIN_CRASH_INTERVAL;
+
// Indicates whether the activity starts logging is enabled.
// Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
volatile boolean mFlagActivityStartsLoggingEnabled;
@@ -650,6 +659,8 @@ final class ActivityManagerConstants extends ContentObserver {
DEFAULT_MEMORY_INFO_THROTTLE_TIME);
TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION,
DEFAULT_TOP_TO_FGS_GRACE_DURATION);
+ MIN_CRASH_INTERVAL = mParser.getInt(KEY_MIN_CRASH_INTERVAL,
+ DEFAULT_MIN_CRASH_INTERVAL);
PENDINGINTENT_WARNING_THRESHOLD = mParser.getInt(KEY_PENDINGINTENT_WARNING_THRESHOLD,
DEFAULT_PENDINGINTENT_WARNING_THRESHOLD);
@@ -866,6 +877,8 @@ final class ActivityManagerConstants extends ContentObserver {
pw.println(MEMORY_INFO_THROTTLE_TIME);
pw.print(" "); pw.print(KEY_TOP_TO_FGS_GRACE_DURATION); pw.print("=");
pw.println(TOP_TO_FGS_GRACE_DURATION);
+ pw.print(" "); pw.print(KEY_MIN_CRASH_INTERVAL); pw.print("=");
+ pw.println(MIN_CRASH_INTERVAL);
pw.print(" "); pw.print(KEY_IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES); pw.print("=");
pw.println(Arrays.toString(IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES.toArray()));
pw.print(" "); pw.print(KEY_IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES); pw.print("=");
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3e600b793385..6e1e3d0a9a9a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1370,6 +1370,10 @@ public class ActivityManagerService extends IActivityManager.Stub
final Injector mInjector;
+ /** The package verifier app. */
+ private String mPackageVerifier;
+ private int mPackageVerifierUid = UserHandle.USER_NULL;
+
static final class ProcessChangeItem {
static final int CHANGE_ACTIVITIES = 1<<0;
static final int CHANGE_FOREGROUND_SERVICES = 1<<1;
@@ -2246,6 +2250,18 @@ public class ActivityManagerService extends IActivityManager.Stub
if (phase == PHASE_SYSTEM_SERVICES_READY) {
mService.mBatteryStatsService.systemServicesReady();
mService.mServices.systemServicesReady();
+ mService.mPackageVerifier = ArrayUtils.firstOrNull(
+ LocalServices.getService(PackageManagerInternal.class).getKnownPackageNames(
+ PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM));
+ if (mService.mPackageVerifier != null) {
+ try {
+ mService.mPackageVerifierUid =
+ getContext().getPackageManager().getPackageUid(
+ mService.mPackageVerifier, UserHandle.USER_SYSTEM);
+ } catch (NameNotFoundException e) {
+ Slog.wtf(TAG, "Package manager couldn't get package verifier uid", e);
+ }
+ }
} else if (phase == PHASE_ACTIVITY_MANAGER_READY) {
mService.startBroadcastObservers();
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
@@ -13263,8 +13279,8 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType, boolean requireForeground, String callingPackage,
- String callingFeatureId, int userId)
+ String resolvedType, boolean requireForeground, boolean hideForegroundNotification,
+ String callingPackage, String callingFeatureId, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
@@ -13276,17 +13292,27 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new IllegalArgumentException("callingPackage cannot be null");
}
+ final int callingUid = Binder.getCallingUid();
+ if (requireForeground && hideForegroundNotification) {
+ if (!UserHandle.isSameApp(callingUid, mPackageVerifierUid)
+ || !callingPackage.equals(mPackageVerifier)) {
+ throw new IllegalArgumentException(
+ "Only the package verifier can hide its foreground service notification");
+ }
+ Slog.i(TAG, "Foreground service notification hiding requested by " + callingPackage);
+ }
+
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
synchronized(this) {
final int callingPid = Binder.getCallingPid();
- final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
- requireForeground, callingPackage, callingFeatureId, userId);
+ requireForeground, hideForegroundNotification,
+ callingPackage, callingFeatureId, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -17670,7 +17696,7 @@ public class ActivityManagerService extends IActivityManager.Stub
ComponentName res;
try {
res = mServices.startServiceLocked(null, service,
- resolvedType, -1, uid, fgRequired, callingPackage,
+ resolvedType, -1, uid, fgRequired, false, callingPackage,
callingFeatureId, userId, allowBackgroundActivityStarts);
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 149e3baa90e7..a512cca7bac4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -654,7 +654,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println("Starting service: " + intent);
pw.flush();
ComponentName cn = mInterface.startService(null, intent, intent.getType(),
- asForeground, SHELL_PACKAGE_NAME, null, mUserId);
+ asForeground, false, SHELL_PACKAGE_NAME, null, mUserId);
if (cn == null) {
err.println("Error: Not found; no service started.");
return -1;
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 2e92ac0fb3d6..5268359df327 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -716,7 +716,7 @@ class AppErrors {
// back in the pending list.
ServiceRecord sr = app.getRunningServiceAt(i);
// If the service was restarted a while ago, then reset crash count, else increment it.
- if (now > sr.restartTime + ProcessList.MIN_CRASH_INTERVAL) {
+ if (now > sr.restartTime + ActivityManagerConstants.MIN_CRASH_INTERVAL) {
sr.crashCount = 1;
} else {
sr.crashCount++;
@@ -729,7 +729,7 @@ class AppErrors {
}
}
- if (crashTime != null && now < crashTime + ProcessList.MIN_CRASH_INTERVAL) {
+ if (crashTime != null && now < crashTime + ActivityManagerConstants.MIN_CRASH_INTERVAL) {
// The process crashed again very quickly. If it was a bound foreground service, let's
// try to restart again in a while, otherwise the process loses!
Slog.w(TAG, "Process " + app.processName
@@ -771,7 +771,7 @@ class AppErrors {
data.taskId = affectedTaskId;
}
if (data != null && crashTimePersistent != null
- && now < crashTimePersistent + ProcessList.MIN_CRASH_INTERVAL) {
+ && now < crashTimePersistent + ActivityManagerConstants.MIN_CRASH_INTERVAL) {
data.repeating = true;
}
}
@@ -853,7 +853,7 @@ class AppErrors {
mAppsNotReportingCrashes.contains(proc.info.packageName);
final long now = SystemClock.uptimeMillis();
final boolean shouldThottle = crashShowErrorTime != null
- && now < crashShowErrorTime + ProcessList.MIN_CRASH_INTERVAL;
+ && now < crashShowErrorTime + ActivityManagerConstants.MIN_CRASH_INTERVAL;
if ((mService.mAtmInternal.canShowErrorDialogs() || showBackground)
&& !crashSilenced && !shouldThottle
&& (showFirstCrash || showFirstCrashDevOption || data.repeating)) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 4673ecde7a68..76089f8fba01 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -154,10 +154,6 @@ public final class ProcessList {
static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
"persist.sys.vold_app_data_isolation_enabled";
- // The minimum time we allow between crashes, for us to consider this
- // application to be bad and stop and its services and reject broadcasts.
- static final int MIN_CRASH_INTERVAL = 60 * 1000;
-
// OOM adjustments for processes in various states:
// Uninitialized value for any major or minor adj fields
@@ -4070,7 +4066,8 @@ public final class ProcessList {
boolean enqueueLocked(ProcessRecord app, String reason, int requester) {
// Throttle the killing request for potential bad app to avoid cpu thrashing
Long last = app.isolated ? null : mLastProcessKillTimes.get(app.processName, app.uid);
- if (last != null && SystemClock.uptimeMillis() < last + MIN_CRASH_INTERVAL) {
+ if ((last != null) && (SystemClock.uptimeMillis()
+ < (last + ActivityManagerConstants.MIN_CRASH_INTERVAL))) {
return false;
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 66677b67b6aa..5b12c8ce6582 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -104,6 +104,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
boolean whitelistManager; // any bindings to this service have BIND_ALLOW_WHITELIST_MANAGEMENT?
boolean delayed; // are we waiting to start this service in the background?
boolean fgRequired; // is the service required to go foreground after starting?
+ boolean hideFgNotification; // Hide the fg service notification
boolean fgWaiting; // is a timeout for going foreground already scheduled?
boolean isForeground; // is service currently in foreground mode?
int foregroundId; // Notification ID of last foreground req.
@@ -836,6 +837,9 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
}
public void postNotification() {
+ if (hideFgNotification) {
+ return;
+ }
final int appUid = appInfo.uid;
final int appPid = app.pid;
if (foregroundId != 0 && foregroundNoti != null) {
@@ -928,7 +932,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
}
if (localForegroundNoti.getSmallIcon() == null) {
// Notifications whose icon is 0 are defined to not show
- // a notification, silently ignoring it. We don't want to
+ // a notification. We don't want to
// just ignore it, we want to prevent the service from
// being foreground.
throw new RuntimeException("invalid service notification: "
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 0a179e89f757..673ca1f3da86 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -285,6 +285,8 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_PLAYBACK_CONFIG_CHANGE = 29;
private static final int MSG_BROADCAST_MICROPHONE_MUTE = 30;
private static final int MSG_CHECK_MODE_FOR_UID = 31;
+ private static final int MSG_STREAM_DEVICES_CHANGED = 32;
+ private static final int MSG_UPDATE_VOLUME_STATES_FOR_DEVICE = 33;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -1283,7 +1285,6 @@ public class AudioService extends IAudioService.Stub
}
if (isPlatformTelevision()) {
- checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, caller);
synchronized (mHdmiClientLock) {
if (mHdmiManager != null && mHdmiPlaybackClient != null) {
updateHdmiCecSinkLocked(mHdmiCecSink | false);
@@ -1303,22 +1304,71 @@ public class AudioService extends IAudioService.Stub
}
}
- private void checkAddAllFixedVolumeDevices(int device, String caller) {
+ /**
+ * Asynchronously update volume states for the given device.
+ *
+ * @param device a single audio device, ensure that this is not a devices bitmask
+ * @param caller caller of this method
+ */
+ private void postUpdateVolumeStatesForAudioDevice(int device, String caller) {
+ sendMsg(mAudioHandler,
+ MSG_UPDATE_VOLUME_STATES_FOR_DEVICE,
+ SENDMSG_QUEUE, device /*arg1*/, 0 /*arg2*/, caller /*obj*/,
+ 0 /*delay*/);
+ }
+
+ /**
+ * Update volume states for the given device.
+ *
+ * This will initialize the volume index if no volume index is available.
+ * If the device is the currently routed device, fixed/full volume policies will be applied.
+ *
+ * @param device a single audio device, ensure that this is not a devices bitmask
+ * @param caller caller of this method
+ */
+ private void onUpdateVolumeStatesForAudioDevice(int device, String caller) {
final int numStreamTypes = AudioSystem.getNumStreamTypes();
- for (int streamType = 0; streamType < numStreamTypes; streamType++) {
- if (!mStreamStates[streamType].hasIndexForDevice(device)) {
- // set the default value, if device is affected by a full/fix/abs volume rule, it
- // will taken into account in checkFixedVolumeDevices()
- mStreamStates[streamType].setIndex(
- mStreamStates[mStreamVolumeAlias[streamType]]
- .getIndex(AudioSystem.DEVICE_OUT_DEFAULT),
- device, caller, true /*hasModifyAudioSettings*/);
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ for (int streamType = 0; streamType < numStreamTypes; streamType++) {
+ updateVolumeStates(device, streamType, caller);
+ }
}
- mStreamStates[streamType].checkFixedVolumeDevices();
+ }
+ }
- // Unmute streams if device is full volume
- if (mFullVolumeDevices.contains(device)) {
- mStreamStates[streamType].mute(false);
+ /**
+ * Update volume states for the given device and given stream.
+ *
+ * This will initialize the volume index if no volume index is available.
+ * If the device is the currently routed device, fixed/full volume policies will be applied.
+ *
+ * @param device a single audio device, ensure that this is not a devices bitmask
+ * @param streamType streamType to be updated
+ * @param caller caller of this method
+ */
+ private void updateVolumeStates(int device, int streamType, String caller) {
+ if (!mStreamStates[streamType].hasIndexForDevice(device)) {
+ // set the default value, if device is affected by a full/fix/abs volume rule, it
+ // will taken into account in checkFixedVolumeDevices()
+ mStreamStates[streamType].setIndex(
+ mStreamStates[mStreamVolumeAlias[streamType]]
+ .getIndex(AudioSystem.DEVICE_OUT_DEFAULT),
+ device, caller, true /*hasModifyAudioSettings*/);
+ }
+
+ // Check if device to be updated is routed for the given audio stream
+ List<AudioDeviceAttributes> devicesForAttributes = getDevicesForAttributesInt(
+ new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build());
+ for (AudioDeviceAttributes deviceAttributes : devicesForAttributes) {
+ if (deviceAttributes.getType() == AudioDeviceInfo.convertInternalDeviceToDeviceType(
+ device)) {
+ mStreamStates[streamType].checkFixedVolumeDevices();
+
+ // Unmute streams if required and device is full volume
+ if (isStreamMute(streamType) && mFullVolumeDevices.contains(device)) {
+ mStreamStates[streamType].mute(false);
+ }
}
}
}
@@ -1868,8 +1918,13 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#getDevicesForAttributes(AudioAttributes) */
public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes(
@NonNull AudioAttributes attributes) {
- Objects.requireNonNull(attributes);
enforceModifyAudioRoutingPermission();
+ return getDevicesForAttributesInt(attributes);
+ }
+
+ protected @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributesInt(
+ @NonNull AudioAttributes attributes) {
+ Objects.requireNonNull(attributes);
return AudioSystem.getDevicesForAttributes(attributes);
}
@@ -4912,11 +4967,21 @@ public class AudioService extends IAudioService.Stub
}
}
- private void observeDevicesForStreams(int skipStream) {
- synchronized (VolumeStreamState.class) {
- for (int stream = 0; stream < mStreamStates.length; stream++) {
- if (stream != skipStream) {
- mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
+ private void onObserveDevicesForAllStreams(int skipStream) {
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ for (int stream = 0; stream < mStreamStates.length; stream++) {
+ if (stream != skipStream) {
+ int devices = mStreamStates[stream].observeDevicesForStream_syncVSS(
+ false /*checkOthers*/);
+
+ Set<Integer> devicesSet = AudioSystem.generateAudioDeviceTypesSet(devices);
+ for (Integer device : devicesSet) {
+ // Update volume states for devices routed for the stream
+ updateVolumeStates(device, stream,
+ "AudioService#onObserveDevicesForAllStreams");
+ }
+ }
}
}
}
@@ -4925,16 +4990,18 @@ public class AudioService extends IAudioService.Stub
/** only public for mocking/spying, do not call outside of AudioService */
@VisibleForTesting
public void postObserveDevicesForAllStreams() {
+ postObserveDevicesForAllStreams(-1);
+ }
+
+ /** only public for mocking/spying, do not call outside of AudioService */
+ @VisibleForTesting
+ public void postObserveDevicesForAllStreams(int skipStream) {
sendMsg(mAudioHandler,
MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS,
- SENDMSG_QUEUE, 0 /*arg1*/, 0 /*arg2*/, null /*obj*/,
+ SENDMSG_QUEUE, skipStream /*arg1*/, 0 /*arg2*/, null /*obj*/,
0 /*delay*/);
}
- private void onObserveDevicesForAllStreams() {
- observeDevicesForStreams(-1);
- }
-
/**
* @see AudioManager#setDeviceVolumeBehavior(AudioDeviceAttributes, int)
* @param device the audio device to be affected
@@ -4985,7 +5052,8 @@ public class AudioService extends IAudioService.Stub
+ Integer.toHexString(audioSystemDeviceOut) + " from:" + caller));
// make sure we have a volume entry for this device, and that volume is updated according
// to volume behavior
- checkAddAllFixedVolumeDevices(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller);
+ postUpdateVolumeStatesForAudioDevice(audioSystemDeviceOut,
+ "setDeviceVolumeBehavior:" + caller);
}
/**
@@ -5616,6 +5684,7 @@ public class AudioService extends IAudioService.Stub
}
}
+ @GuardedBy("VolumeStreamState.class")
public int observeDevicesForStream_syncVSS(boolean checkOthers) {
if (!mSystemServer.isPrivileged()) {
return AudioSystem.DEVICE_NONE;
@@ -5628,15 +5697,19 @@ public class AudioService extends IAudioService.Stub
mObservedDevices = devices;
if (checkOthers) {
// one stream's devices have changed, check the others
- observeDevicesForStreams(mStreamType);
+ postObserveDevicesForAllStreams(mStreamType);
}
// log base stream changes to the event log
if (mStreamVolumeAlias[mStreamType] == mStreamType) {
EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
}
- sendBroadcastToAll(mStreamDevicesChanged
- .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
- .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
+ // send STREAM_DEVICES_CHANGED_ACTION on the message handler so it is scheduled after
+ // the postObserveDevicesForStreams is handled
+ sendMsg(mAudioHandler,
+ MSG_STREAM_DEVICES_CHANGED,
+ SENDMSG_QUEUE, prevDevices /*arg1*/, devices /*arg2*/,
+ // ok to send reference to this object, it is final
+ mStreamDevicesChanged /*obj*/, 0 /*delay*/);
return devices;
}
@@ -6408,7 +6481,7 @@ public class AudioService extends IAudioService.Stub
break;
case MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS:
- onObserveDevicesForAllStreams();
+ onObserveDevicesForAllStreams(/*skipStream*/ msg.arg1);
break;
case MSG_HDMI_VOLUME_CHECK:
@@ -6451,6 +6524,16 @@ public class AudioService extends IAudioService.Stub
mModeLogger.log(new PhoneStateEvent(h.getPackage(), h.getPid()));
}
break;
+
+ case MSG_STREAM_DEVICES_CHANGED:
+ sendBroadcastToAll(((Intent) msg.obj)
+ .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, msg.arg1)
+ .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, msg.arg2));
+ break;
+
+ case MSG_UPDATE_VOLUME_STATES_FOR_DEVICE:
+ onUpdateVolumeStatesForAudioDevice(msg.arg1, (String) msg.obj);
+ break;
}
}
}
@@ -7207,10 +7290,9 @@ public class AudioService extends IAudioService.Stub
// HDMI output
removeAudioSystemDeviceOutFromFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI);
}
+ postUpdateVolumeStatesForAudioDevice(AudioSystem.DEVICE_OUT_HDMI,
+ "HdmiPlaybackClient.DisplayStatusCallback");
}
-
- checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI,
- "HdmiPlaybackClient.DisplayStatusCallback");
}
private class MyHdmiControlStatusChangeListenerCallback
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 7f9b3c9fcff7..a75a80a606eb 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -21,23 +21,14 @@ import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.INTERNET;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
-import static android.net.INetd.PERMISSION_INTERNET;
-import static android.net.INetd.PERMISSION_NETWORK;
-import static android.net.INetd.PERMISSION_NONE;
-import static android.net.INetd.PERMISSION_SYSTEM;
-import static android.net.INetd.PERMISSION_UNINSTALLED;
-import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS;
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.internal.util.ArrayUtils.convertToIntArray;
-
import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -56,9 +47,11 @@ 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.server.LocalServices;
import com.android.server.SystemConfig;
@@ -72,6 +65,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+
/**
* A utility class to inform Netd of UID permisisons.
* Does a mass update at boot and then monitors for app install/remove.
@@ -120,51 +114,9 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
public int getDeviceFirstSdkInt() {
return Build.VERSION.FIRST_SDK_INT;
}
-
- /**
- * Check whether given uid has specific permission.
- */
- public int uidPermission(@NonNull final String permission, final int uid) {
- return ActivityManager.checkUidPermission(permission, uid);
- }
}
- /**
- * A data class to store each uid Netd permission information. Netd permissions includes
- * PERMISSION_NETWORK, PERMISSION_SYSTEM, PERMISSION_INTERNET, PERMISSION_UPDATE_DEVICE_STATS
- * and OR'd with the others. Default permission is PERMISSION_NONE and PERMISSION_UNINSTALLED
- * will be set if all packages are removed from the uid.
- */
- public static class UidNetdPermissionInfo {
- private final int mNetdPermissions;
-
- UidNetdPermissionInfo() {
- this(PERMISSION_NONE);
- }
-
- UidNetdPermissionInfo(int permissions) {
- mNetdPermissions = permissions;
- }
-
- /** Plus given permissions and return new UidNetdPermissionInfo instance. */
- public UidNetdPermissionInfo plusNetdPermissions(int permissions) {
- return new UidNetdPermissionInfo(mNetdPermissions | permissions);
- }
-
- /** Return whether package is uninstalled. */
- public boolean isPackageUninstalled() {
- return mNetdPermissions == PERMISSION_UNINSTALLED;
- }
-
- /** Check that uid has given permissions */
- public boolean hasNetdPermissions(final int permissions) {
- if (isPackageUninstalled()) return false;
- if (permissions == PERMISSION_NONE) return true;
- return (mNetdPermissions & permissions) == permissions;
- }
- }
-
- public PermissionMonitor(Context context, INetd netd) {
+ public PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd) {
this(context, netd, new Dependencies());
}
@@ -195,7 +147,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
return;
}
- final SparseArray<UidNetdPermissionInfo> netdPermsUids = new SparseArray<>();
+ SparseIntArray netdPermsUids = new SparseIntArray();
for (PackageInfo app : apps) {
int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
@@ -204,9 +156,8 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
}
mAllApps.add(UserHandle.getAppId(uid));
- final boolean isNetwork = hasPermission(CHANGE_NETWORK_STATE, uid);
- final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(uid)
- || isCarryoverPackage(app.applicationInfo);
+ boolean isNetwork = hasNetworkPermission(app);
+ boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
if (isNetwork || hasRestrictedPermission) {
Boolean permission = mApps.get(uid);
@@ -217,13 +168,10 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
}
}
- // Skip already checked uid.
- if (netdPermsUids.get(uid) != null) continue;
-
//TODO: unify the management of the permissions into one codepath.
- final UidNetdPermissionInfo permInfo =
- new UidNetdPermissionInfo(getNetdPermissionMask(uid));
- netdPermsUids.put(uid, permInfo);
+ int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions,
+ app.requestedPermissionsFlags);
+ netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
}
List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users
@@ -238,17 +186,15 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
for (int i = 0; i < systemPermission.size(); i++) {
ArraySet<String> perms = systemPermission.valueAt(i);
int uid = systemPermission.keyAt(i);
- int netdPermission = PERMISSION_NONE;
+ 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)
- ? PERMISSION_UPDATE_DEVICE_STATS : 0;
- netdPermission |= perms.contains(INTERNET) ? PERMISSION_INTERNET : 0;
+ ? INetd.PERMISSION_UPDATE_DEVICE_STATS : 0;
+ netdPermission |= perms.contains(INTERNET)
+ ? INetd.PERMISSION_INTERNET : 0;
}
- final UidNetdPermissionInfo permInfo = netdPermsUids.get(uid);
- netdPermsUids.put(uid, permInfo != null
- ? permInfo.plusNetdPermissions(netdPermission)
- : new UidNetdPermissionInfo(netdPermission));
+ netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
}
log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
update(mUsers, mApps, true);
@@ -261,34 +207,48 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
}
@VisibleForTesting
- boolean hasPermission(@NonNull final String permission, final int uid) {
- return mDeps.uidPermission(permission, uid) == PackageManager.PERMISSION_GRANTED;
+ boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) {
+ if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
+ return false;
+ }
+ final int index = ArrayUtils.indexOf(app.requestedPermissions, permission);
+ if (index < 0 || index >= app.requestedPermissionsFlags.length) return false;
+ return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0;
}
@VisibleForTesting
- // TODO : remove this check in the future(b/162295056). All apps should just request the
- // appropriate permission for their use case since android Q.
- boolean isCarryoverPackage(@Nullable final ApplicationInfo appInfo) {
- if (appInfo == null) return false;
- return (appInfo.targetSdkVersion < VERSION_Q && isVendorApp(appInfo))
- // Backward compatibility for b/114245686, on devices that launched before Q daemons
- // and apps running as the system UID are exempted from this check.
- || (appInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q);
+ boolean hasNetworkPermission(@NonNull final PackageInfo app) {
+ return hasPermission(app, CHANGE_NETWORK_STATE);
}
@VisibleForTesting
- boolean hasRestrictedNetworkPermission(final int uid) {
- return hasPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, uid)
- || hasPermission(PERMISSION_MAINLINE_NETWORK_STACK, uid)
- || hasPermission(NETWORK_STACK, uid);
+ boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) {
+ // TODO : remove this check in the future(b/31479477). All apps should just
+ // request the appropriate permission for their use case since android Q.
+ if (app.applicationInfo != null) {
+ // Backward compatibility for b/114245686, on devices that launched before Q daemons
+ // and apps running as the system UID are exempted from this check.
+ if (app.applicationInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q) {
+ return true;
+ }
+
+ if (app.applicationInfo.targetSdkVersion < VERSION_Q
+ && isVendorApp(app.applicationInfo)) {
+ return true;
+ }
+ }
+
+ return hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK)
+ || hasPermission(app, NETWORK_STACK)
+ || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
}
/** Returns whether the given uid has using background network permission. */
public synchronized boolean hasUseBackgroundNetworksPermission(final int uid) {
// Apps with any of the CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_INTERNAL or
// CONNECTIVITY_USE_RESTRICTED_NETWORKS permission has the permission to use background
- // networks. mApps contains the result of checks for both CHANGE_NETWORK_STATE permission
- // and hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of
+ // networks. mApps contains the result of checks for both hasNetworkPermission and
+ // hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of
// permissions at least.
return mApps.containsKey(uid);
}
@@ -313,11 +273,11 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
}
try {
if (add) {
- mNetd.networkSetPermissionForUser(PERMISSION_NETWORK, convertToIntArray(network));
- mNetd.networkSetPermissionForUser(PERMISSION_SYSTEM, convertToIntArray(system));
+ mNetd.networkSetPermissionForUser(INetd.PERMISSION_NETWORK, toIntArray(network));
+ mNetd.networkSetPermissionForUser(INetd.PERMISSION_SYSTEM, toIntArray(system));
} else {
- mNetd.networkClearPermissionForUser(convertToIntArray(network));
- mNetd.networkClearPermissionForUser(convertToIntArray(system));
+ mNetd.networkClearPermissionForUser(toIntArray(network));
+ mNetd.networkClearPermissionForUser(toIntArray(system));
}
} catch (RemoteException e) {
loge("Exception when updating permissions: " + e);
@@ -363,15 +323,14 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
}
@VisibleForTesting
- protected Boolean highestPermissionForUid(Boolean currentPermission, String name, int uid) {
+ protected Boolean highestPermissionForUid(Boolean currentPermission, String name) {
if (currentPermission == SYSTEM) {
return currentPermission;
}
try {
final PackageInfo app = mPackageManager.getPackageInfo(name, GET_PERMISSIONS);
- final boolean isNetwork = hasPermission(CHANGE_NETWORK_STATE, uid);
- final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(uid)
- || isCarryoverPackage(app.applicationInfo);
+ final boolean isNetwork = hasNetworkPermission(app);
+ final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
if (isNetwork || hasRestrictedPermission) {
currentPermission = hasRestrictedPermission;
}
@@ -382,15 +341,24 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
return currentPermission;
}
- private UidNetdPermissionInfo getPermissionForUid(final int uid) {
+ private int getPermissionForUid(final int uid) {
+ int permission = INetd.PERMISSION_NONE;
// Check all the packages for this UID. The UID has the permission if any of the
// packages in it has the permission.
final String[] packages = mPackageManager.getPackagesForUid(uid);
- if (packages == null || packages.length <= 0) {
+ if (packages != null && packages.length > 0) {
+ for (String name : packages) {
+ final PackageInfo app = getPackageInfo(name);
+ if (app != null && app.requestedPermissions != null) {
+ permission |= getNetdPermissionMask(app.requestedPermissions,
+ app.requestedPermissionsFlags);
+ }
+ }
+ } else {
// The last package of this uid is removed from device. Clean the package up.
- return new UidNetdPermissionInfo(PERMISSION_UNINSTALLED);
+ permission = INetd.PERMISSION_UNINSTALLED;
}
- return new UidNetdPermissionInfo(getNetdPermissionMask(uid));
+ return permission;
}
/**
@@ -407,7 +375,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
// If multiple packages share a UID (cf: android:sharedUserId) and ask for different
// permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
- final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName, uid);
+ final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName);
if (permission != mApps.get(uid)) {
mApps.put(uid, permission);
@@ -463,7 +431,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
String[] packages = mPackageManager.getPackagesForUid(uid);
if (packages != null && packages.length > 0) {
for (String name : packages) {
- permission = highestPermissionForUid(permission, name, uid);
+ permission = highestPermissionForUid(permission, name);
if (permission == SYSTEM) {
// An app with this UID still has the SYSTEM permission.
// Therefore, this UID must already have the SYSTEM permission.
@@ -499,13 +467,19 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
}
- private int getNetdPermissionMask(final int uid) {
- int permissions = PERMISSION_NONE;
- if (hasPermission(INTERNET, uid)) {
- permissions |= PERMISSION_INTERNET;
- }
- if (hasPermission(UPDATE_DEVICE_STATS, uid)) {
- permissions |= PERMISSION_UPDATE_DEVICE_STATS;
+ private static int getNetdPermissionMask(String[] requestedPermissions,
+ int[] requestedPermissionsFlags) {
+ int permissions = 0;
+ if (requestedPermissions == null || requestedPermissionsFlags == null) return permissions;
+ for (int i = 0; i < requestedPermissions.length; i++) {
+ if (requestedPermissions[i].equals(INTERNET)
+ && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
+ permissions |= INetd.PERMISSION_INTERNET;
+ }
+ if (requestedPermissions[i].equals(UPDATE_DEVICE_STATS)
+ && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
+ permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
+ }
}
return permissions;
}
@@ -640,28 +614,28 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
* permission information to netd.
*
* @param uid the app uid of the package installed
- * @param permissionInfo the permission info of given uid.
+ * @param permissions the permissions the app requested and netd cares about.
*
* @hide
*/
@VisibleForTesting
- void sendPackagePermissionsForUid(int uid, UidNetdPermissionInfo permissionInfo) {
- final SparseArray<UidNetdPermissionInfo> uidsPermInfo = new SparseArray<>();
- uidsPermInfo.put(uid, permissionInfo);
- sendPackagePermissionsToNetd(uidsPermInfo);
+ void sendPackagePermissionsForUid(int uid, int permissions) {
+ SparseIntArray netdPermissionsAppIds = new SparseIntArray();
+ netdPermissionsAppIds.put(uid, permissions);
+ sendPackagePermissionsToNetd(netdPermissionsAppIds);
}
/**
* Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET
* and/or UPDATE_DEVICE_STATS permission of the uids in array.
*
- * @param uidsPermInfo permission info array generated from each uid. If the uid permission is
- * PERMISSION_NONE or PERMISSION_UNINSTALLED, revoke all permissions of that
- * uid.
+ * @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the
+ * permission is 0, revoke all permissions of that uid.
+ *
* @hide
*/
@VisibleForTesting
- void sendPackagePermissionsToNetd(final SparseArray<UidNetdPermissionInfo> uidsPermInfo) {
+ void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
if (mNetd == null) {
Log.e(TAG, "Failed to get the netd service");
return;
@@ -671,44 +645,50 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
ArrayList<Integer> noPermissionAppIds = new ArrayList<>();
ArrayList<Integer> uninstalledAppIds = new ArrayList<>();
- for (int i = 0; i < uidsPermInfo.size(); i++) {
- final int uid = uidsPermInfo.keyAt(i);
- final UidNetdPermissionInfo permInfo = uidsPermInfo.valueAt(i);
- if (permInfo.hasNetdPermissions(
- PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS)) {
- allPermissionAppIds.add(uid);
- } else if (permInfo.hasNetdPermissions(PERMISSION_INTERNET)) {
- internetPermissionAppIds.add(uid);
- } else if (permInfo.hasNetdPermissions(PERMISSION_UPDATE_DEVICE_STATS)) {
- updateStatsPermissionAppIds.add(uid);
- } else if (permInfo.isPackageUninstalled()) {
- uninstalledAppIds.add(uid);
- } else {
- noPermissionAppIds.add(uid);
+ for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
+ int permissions = netdPermissionsAppIds.valueAt(i);
+ switch(permissions) {
+ case (INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS):
+ allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ case INetd.PERMISSION_INTERNET:
+ internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ case INetd.PERMISSION_UPDATE_DEVICE_STATS:
+ updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ case INetd.PERMISSION_NONE:
+ noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ case INetd.PERMISSION_UNINSTALLED:
+ uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
+ default:
+ Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
+ + netdPermissionsAppIds.keyAt(i));
}
}
try {
// TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids()
if (allPermissionAppIds.size() != 0) {
mNetd.trafficSetNetPermForUids(
- PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS,
- convertToIntArray(allPermissionAppIds));
+ INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ ArrayUtils.convertToIntArray(allPermissionAppIds));
}
if (internetPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(PERMISSION_INTERNET,
- convertToIntArray(internetPermissionAppIds));
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
+ ArrayUtils.convertToIntArray(internetPermissionAppIds));
}
if (updateStatsPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(PERMISSION_UPDATE_DEVICE_STATS,
- convertToIntArray(updateStatsPermissionAppIds));
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
}
if (noPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(PERMISSION_NONE,
- convertToIntArray(noPermissionAppIds));
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE,
+ ArrayUtils.convertToIntArray(noPermissionAppIds));
}
if (uninstalledAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(PERMISSION_UNINSTALLED,
- convertToIntArray(uninstalledAppIds));
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED,
+ ArrayUtils.convertToIntArray(uninstalledAppIds));
}
} catch (RemoteException e) {
Log.e(TAG, "Pass appId list of special permission failed." + e);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 041bedc3c575..ec12a971e445 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -210,6 +210,7 @@ public class SyncManager {
private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock";
+ private static final boolean USE_WTF_FOR_ACCOUNT_ERROR = false;
private static final int SYNC_OP_STATE_VALID = 0;
// "1" used to include errors 3, 4 and 5 but now it's split up.
@@ -3446,7 +3447,7 @@ public class SyncManager {
if (isLoggable) {
Slog.v(TAG, " Dropping sync operation: account doesn't exist.");
}
- Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: account doesn't exist.");
+ logAccountError("SYNC_OP_STATE_INVALID: account doesn't exist.");
return SYNC_OP_STATE_INVALID_NO_ACCOUNT;
}
// Drop this sync request if it isn't syncable.
@@ -3456,14 +3457,14 @@ public class SyncManager {
Slog.v(TAG, " Dropping sync operation: "
+ "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
}
- Slog.wtf(TAG, "SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS");
+ logAccountError("SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS");
return SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS;
}
if (state == AuthorityInfo.NOT_SYNCABLE) {
if (isLoggable) {
Slog.v(TAG, " Dropping sync operation: isSyncable == NOT_SYNCABLE");
}
- Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: NOT_SYNCABLE");
+ logAccountError("SYNC_OP_STATE_INVALID: NOT_SYNCABLE");
return SYNC_OP_STATE_INVALID_NOT_SYNCABLE;
}
@@ -3482,12 +3483,20 @@ public class SyncManager {
if (isLoggable) {
Slog.v(TAG, " Dropping sync operation: disallowed by settings/network.");
}
- Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: disallowed by settings/network");
+ logAccountError("SYNC_OP_STATE_INVALID: disallowed by settings/network");
return SYNC_OP_STATE_INVALID_SYNC_DISABLED;
}
return SYNC_OP_STATE_VALID;
}
+ private void logAccountError(String message) {
+ if (USE_WTF_FOR_ACCOUNT_ERROR) {
+ Slog.wtf(TAG, message);
+ } else {
+ Slog.e(TAG, message);
+ }
+ }
+
private boolean dispatchSyncOperation(SyncOperation op) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.v(TAG, "dispatchSyncOperation: we are going to sync " + op);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 9ab410d258cc..3fddd5ab91ee 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2591,7 +2591,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
mCurMethod = IInputMethod.Stub.asInterface(service);
final String curMethodPackage = mCurIntent.getComponent().getPackageName();
- final int curMethodUid = mPackageManagerInternal.getPackageUidInternal(
+ final int curMethodUid = mPackageManagerInternal.getPackageUid(
curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId());
if (curMethodUid < 0) {
Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage);
diff --git a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
index e3074dba26ef..ddd56c890c2f 100644
--- a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
+++ b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
@@ -123,6 +123,10 @@ public class BiometricDeferredQueue {
final VerifyCredentialResponse response = spManager.verifyChallengeInternal(
getGatekeeperService(), userAuthInfo.gatekeeperPassword, challenge,
userAuthInfo.userId);
+ if (response == null) {
+ Slog.wtf(TAG, "VerifyChallenge failed, null response");
+ continue;
+ }
if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
Slog.wtf(TAG, "VerifyChallenge failed, response: "
+ response.getResponseCode());
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 0044d8936841..26c3132167d3 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -33,7 +33,7 @@ import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HA
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.internal.widget.LockPatternUtils.USER_FRP;
-import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW;
+import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE;
import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled;
import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential;
@@ -104,6 +104,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
+import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -123,7 +124,6 @@ import com.android.internal.widget.VerifyCredentialResponse;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
import com.android.server.locksettings.LockSettingsStorage.PersistentData;
import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
@@ -155,6 +155,7 @@ import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.Random;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -186,6 +187,14 @@ public class LockSettingsService extends ILockSettings.Stub {
private static final String SYNTHETIC_PASSWORD_UPDATE_TIME_KEY = "sp-handle-ts";
private static final String USER_SERIAL_NUMBER_KEY = "serial-number";
+ // Duration that LockSettingsService will store the gatekeeper password for. This allows
+ // multiple biometric enrollments without prompting the user to enter their password via
+ // ConfirmLockPassword/ConfirmLockPattern multiple times. This needs to be at least the duration
+ // from the start of the first biometric sensor's enrollment to the start of the last biometric
+ // sensor's enrollment. If biometric enrollment requests a password handle that has expired, the
+ // user's credential must be presented again, e.g. via ConfirmLockPattern/ConfirmLockPassword.
+ private static final int GK_PW_HANDLE_STORE_DURATION_MS = 10 * 60 * 1000; // 10 minutes
+
// Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
// Do not call into ActivityManager while holding mSpManager lock.
private final Object mSeparateChallengeLock = new Object();
@@ -202,6 +211,8 @@ public class LockSettingsService extends ILockSettings.Stub {
private final LockSettingsStrongAuth mStrongAuth;
private final SynchronizedStrongAuthTracker mStrongAuthTracker;
private final BiometricDeferredQueue mBiometricDeferredQueue;
+ private final LongSparseArray<byte[]> mGatekeeperPasswords;
+ private final Random mRandom;
private final NotificationManager mNotificationManager;
private final UserManager mUserManager;
@@ -559,6 +570,8 @@ public class LockSettingsService extends ILockSettings.Stub {
mStorageManager = injector.getStorageManager();
mStrongAuthTracker = injector.getStrongAuthTracker();
mStrongAuthTracker.register(mStrongAuth);
+ mGatekeeperPasswords = new LongSparseArray<>();
+ mRandom = new SecureRandom();
mSpManager = injector.getSyntheticPasswordManager(mStorage);
mManagedProfilePasswordCache = injector.getManagedProfilePasswordCache();
@@ -1017,7 +1030,7 @@ public class LockSettingsService extends ILockSettings.Stub {
mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
}
- private final void checkPasswordReadPermission(int userId) {
+ private final void checkPasswordReadPermission() {
mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
}
@@ -1077,7 +1090,9 @@ public class LockSettingsService extends ILockSettings.Stub {
public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
LockscreenCredential managedUserPassword) {
checkWritePermission(userId);
- if (!mHasSecureLockScreen) {
+ if (!mHasSecureLockScreen
+ && managedUserPassword != null
+ && managedUserPassword.getType() != CREDENTIAL_TYPE_NONE) {
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature.");
}
@@ -1547,7 +1562,8 @@ public class LockSettingsService extends ILockSettings.Stub {
public boolean setLockCredential(LockscreenCredential credential,
LockscreenCredential savedCredential, int userId) {
- if (!mHasSecureLockScreen) {
+ if (!mHasSecureLockScreen
+ && credential != null && credential.getType() != CREDENTIAL_TYPE_NONE) {
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature");
}
@@ -1923,7 +1939,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public VerifyCredentialResponse checkCredential(LockscreenCredential credential, int userId,
ICheckCredentialProgressCallback progressCallback) {
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
try {
return doVerifyCredential(credential, userId, progressCallback, 0 /* flags */);
} finally {
@@ -1935,7 +1951,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@Nullable
public VerifyCredentialResponse verifyCredential(LockscreenCredential credential,
int userId, int flags) {
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
try {
return doVerifyCredential(credential, userId, null /* progressCallback */, flags);
} finally {
@@ -1944,18 +1960,36 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@Override
- public VerifyCredentialResponse verifyGatekeeperPassword(byte[] gatekeeperPassword,
+ public VerifyCredentialResponse verifyGatekeeperPasswordHandle(long gatekeeperPasswordHandle,
long challenge, int userId) {
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
+
+ final VerifyCredentialResponse response;
+ final byte[] gatekeeperPassword;
+
+ synchronized (mGatekeeperPasswords) {
+ gatekeeperPassword = mGatekeeperPasswords.get(gatekeeperPasswordHandle);
+ }
- VerifyCredentialResponse response;
synchronized (mSpManager) {
- response = mSpManager.verifyChallengeInternal(getGateKeeperService(),
- gatekeeperPassword, challenge, userId);
+ if (gatekeeperPassword == null) {
+ response = VerifyCredentialResponse.ERROR;
+ } else {
+ response = mSpManager.verifyChallengeInternal(getGateKeeperService(),
+ gatekeeperPassword, challenge, userId);
+ }
}
return response;
}
+ @Override
+ public void removeGatekeeperPasswordHandle(long gatekeeperPasswordHandle) {
+ checkPasswordReadPermission();
+ synchronized (mGatekeeperPasswords) {
+ mGatekeeperPasswords.remove(gatekeeperPasswordHandle);
+ }
+ }
+
/*
* Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero
* format.
@@ -2012,7 +2046,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public VerifyCredentialResponse verifyTiedProfileChallenge(LockscreenCredential credential,
int userId, @LockPatternUtils.VerifyFlag int flags) {
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
if (!isManagedProfileWithUnifiedLock(userId)) {
throw new IllegalArgumentException("User id must be managed profile with unified lock");
}
@@ -2179,7 +2213,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
mFirstCallToVold = false;
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
// There's no guarantee that this will safely connect, but if it fails
// we will simply show the lock screen when we shouldn't, so relatively
@@ -2269,13 +2303,13 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
- checkPasswordReadPermission(UserHandle.USER_ALL);
+ checkPasswordReadPermission();
mStrongAuth.registerStrongAuthTracker(tracker);
}
@Override
public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
- checkPasswordReadPermission(UserHandle.USER_ALL);
+ checkPasswordReadPermission();
mStrongAuth.unregisterStrongAuthTracker(tracker);
}
@@ -2305,7 +2339,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public int getStrongAuthForUser(int userId) {
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
return mStrongAuthTracker.getStrongAuthForUser(userId);
}
@@ -2648,7 +2682,7 @@ public class LockSettingsService extends ILockSettings.Stub {
final AuthenticationResult authResult;
VerifyCredentialResponse response;
- final boolean returnGkPw = (flags & VERIFY_FLAG_RETURN_GK_PW) != 0;
+ final boolean requestGkPw = (flags & VERIFY_FLAG_REQUEST_GK_PW_HANDLE) != 0;
synchronized (mSpManager) {
if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
@@ -2690,14 +2724,43 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- if (response.isMatched() && returnGkPw) {
- return new VerifyCredentialResponse.Builder()
- .setGatekeeperPassword(authResult.authToken.deriveGkPassword()).build();
+ if (response.isMatched() && requestGkPw) {
+ final long handle = storeGatekeeperPasswordTemporarily(
+ authResult.authToken.deriveGkPassword());
+ return new VerifyCredentialResponse.Builder().setGatekeeperPasswordHandle(handle)
+ .build();
} else {
return response;
}
}
+ /**
+ * Stores the gatekeeper password temporarily.
+ * @param gatekeeperPassword unlocked upon successful Synthetic Password
+ * @return non-zero handle to the gatekeeper password, which can be used for a set amount of
+ * time.
+ */
+ private long storeGatekeeperPasswordTemporarily(byte[] gatekeeperPassword) {
+ long handle = 0L;
+
+ synchronized (mGatekeeperPasswords) {
+ while (handle == 0L || mGatekeeperPasswords.get(handle) != null) {
+ handle = mRandom.nextLong();
+ }
+ mGatekeeperPasswords.put(handle, gatekeeperPassword);
+ }
+
+ final long finalHandle = handle;
+ mHandler.postDelayed(() -> {
+ synchronized (mGatekeeperPasswords) {
+ Slog.d(TAG, "Removing handle: " + finalHandle);
+ mGatekeeperPasswords.remove(finalHandle);
+ }
+ }, GK_PW_HANDLE_STORE_DURATION_MS);
+
+ return handle;
+ }
+
private void onCredentialVerified(AuthenticationToken authToken, PasswordMetrics metrics,
int userId) {
@@ -2935,7 +2998,7 @@ public class LockSettingsService extends ILockSettings.Stub {
*/
@Override
public byte[] getHashFactor(LockscreenCredential currentCredential, int userId) {
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
try {
if (isManagedProfileWithUnifiedLock(userId)) {
try {
@@ -3013,7 +3076,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public boolean hasPendingEscrowToken(int userId) {
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
synchronized (mSpManager) {
return !mSpManager.getPendingTokensForUser(userId).isEmpty();
}
@@ -3199,6 +3262,8 @@ public class LockSettingsService extends ILockSettings.Stub {
mRebootEscrowManager.dump(pw);
pw.println();
pw.decreaseIndent();
+
+ pw.println("PasswordHandleCount: " + mGatekeeperPasswords.size());
}
/**
@@ -3361,7 +3426,8 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public boolean setLockCredentialWithToken(LockscreenCredential credential, long tokenHandle,
byte[] token, int userId) {
- if (!mHasSecureLockScreen) {
+ if (!mHasSecureLockScreen
+ && credential != null && credential.getType() != CREDENTIAL_TYPE_NONE) {
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature.");
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
index 0575ac6315a1..d202a2a60738 100644
--- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -100,11 +100,16 @@ public class NetworkStatsSubscriptionsMonitor extends
if (match != null) continue;
// Create listener for every newly added sub. Also store subscriberId into it to
- // prevent binder call to telephony when querying RAT.
+ // prevent binder call to telephony when querying RAT. If the subscriberId is empty
+ // for any reason, such as SIM PIN locked, skip registration.
+ // SubscriberId will be unavailable again if 1. modem crashed 2. reboot
+ // 3. re-insert SIM. If that happens, the listeners will be eventually synchronized
+ // with active sub list once all subscriberIds are ready.
final String subscriberId = mTeleManager.getSubscriberId(subId);
if (TextUtils.isEmpty(subscriberId)) {
- Log.wtf(NetworkStatsService.TAG,
- "Empty subscriberId for newly added sub: " + subId);
+ Log.d(NetworkStatsService.TAG, "Empty subscriberId for newly added sub "
+ + subId + ", skip listener registration");
+ continue;
}
final RatTypeListener listener =
new RatTypeListener(mExecutor, this, subId, subscriberId);
@@ -113,6 +118,7 @@ public class NetworkStatsSubscriptionsMonitor extends
// Register listener to the telephony manager that associated with specific sub.
mTeleManager.createForSubscriptionId(subId)
.listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE);
+ Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + subId);
}
for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) {
@@ -165,6 +171,7 @@ public class NetworkStatsSubscriptionsMonitor extends
private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) {
mTeleManager.createForSubscriptionId(listener.mSubId)
.listen(listener, PhoneStateListener.LISTEN_NONE);
+ Log.d(NetworkStatsService.TAG, "RAT type listener unregistered for sub " + listener.mSubId);
mRatListeners.remove(listener);
// Removal of subscriptions doesn't generate RAT changed event, fire it for every
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 9f9235dc852f..04658555f22b 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6103,7 +6103,8 @@ public class NotificationManagerService extends SystemService {
protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
if (isBlocked(r)) {
if (DBG) {
- Slog.e(TAG, "Suppressing notification from package by user request.");
+ Slog.e(TAG, "Suppressing notification from package " + r.getSbn().getPackageName()
+ + " by user request.");
}
usageStats.registerBlocked(r);
return true;
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index 617f6879e65e..a234f5ac3f3e 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -605,7 +605,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
private boolean isPlatformSignedAppWithAutomaticProfilesPermission(
String packageName, int[] profileIds) {
for (int userId : profileIds) {
- final int uid = mInjector.getPackageManagerInternal().getPackageUidInternal(
+ final int uid = mInjector.getPackageManagerInternal().getPackageUid(
packageName, /* flags= */ 0, userId);
if (uid == -1) {
continue;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 28c5e964fe27..ed62362b04fb 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -134,6 +134,7 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.DexManager;
@@ -1325,6 +1326,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
final int sessionIndex = mChildSessionsRemaining.indexOfKey(sessionId);
+ final String message = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
if (PackageInstaller.STATUS_SUCCESS == status) {
mChildSessionsRemaining.removeAt(sessionIndex);
if (mChildSessionsRemaining.size() == 0) {
@@ -1341,10 +1343,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
PackageInstallerSession.this.sessionId);
mChildSessionsRemaining.clear(); // we're done. Don't send any more.
- try {
- mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
- } catch (IntentSender.SendIntentException ignore) {
- }
+ destroyInternal();
+ dispatchSessionFinished(INSTALL_FAILED_INTERNAL_ERROR,
+ "Child session " + sessionId + " failed: " + message, null);
}
});
}
@@ -1554,12 +1555,28 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
private void onSessionValidationFailure(int error, String detailMessage) {
- // Session is sealed but could not be verified, we need to destroy it.
+ // Session is sealed but could not be validated, we need to destroy it.
destroyInternal();
// Dispatch message to remove session from PackageInstallerService.
dispatchSessionFinished(error, detailMessage, null);
}
+ private void onSessionVerificationFailure(int error, String detailMessage) {
+ Slog.e(TAG, "Failed to verify session " + sessionId + " [" + detailMessage + "]");
+ // Session is sealed and committed but could not be verified, we need to destroy it.
+ destroyInternal();
+ if (isStaged()) {
+ setStagedSessionFailed(
+ SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, detailMessage);
+ // TODO(b/136257624): Remove this once all verification logic has been transferred out
+ // of StagingManager.
+ mStagingManager.notifyVerificationComplete(sessionId);
+ } else {
+ // Dispatch message to remove session from PackageInstallerService.
+ dispatchSessionFinished(error, detailMessage, null);
+ }
+ }
+
private void onStorageUnhealthy() {
final String packageName = getPackageName();
if (TextUtils.isEmpty(packageName)) {
@@ -1680,7 +1697,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
if (params.isStaged) {
mStagingManager.commitSession(this);
- destroyInternal();
+ // TODO(b/136257624): CTS test fails if we don't send session finished broadcast, even
+ // though ideally, we just need to send session committed broadcast.
dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
return;
}
@@ -1691,14 +1709,30 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
"APEX packages can only be installed using staged sessions.", null);
return;
}
+ verify();
+ }
+ /**
+ * Resumes verification process for non-final committed staged session.
+ *
+ * Useful if a device gets rebooted before verification is complete and we need to restart the
+ * verification.
+ */
+ void verifyStagedSession() {
+ assertCallerIsOwnerOrRootOrSystemLocked();
+ Preconditions.checkArgument(isCommitted());
+ Preconditions.checkArgument(isStaged());
+ Preconditions.checkArgument(!mStagedSessionApplied && !mStagedSessionFailed);
+
+ verify();
+ }
+
+ private void verify() {
try {
verifyNonStaged();
} catch (PackageManagerException e) {
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
- Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
- destroyInternal();
- dispatchSessionFinished(e.error, completeMsg, null);
+ onSessionVerificationFailure(e.error, completeMsg);
}
}
@@ -1846,7 +1880,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock")
private PackageManagerService.VerificationParams makeVerificationParamsLocked()
throws PackageManagerException {
- if (!params.isMultiPackage) {
+ // TODO(b/136257624): Some logic in this if block probably belongs in
+ // makeInstallParams().
+ if (!params.isMultiPackage && !isApexInstallation()) {
Objects.requireNonNull(mPackageName);
Objects.requireNonNull(mSigningDetails);
Objects.requireNonNull(mResolvedBaseFile);
@@ -1923,8 +1959,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (returnCode == PackageManager.INSTALL_SUCCEEDED) {
onVerificationComplete();
} else {
- destroyInternal();
- dispatchSessionFinished(returnCode, msg, extras);
+ onSessionVerificationFailure(returnCode, msg);
}
}
};
@@ -1946,9 +1981,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
private void onVerificationComplete() {
- if ((params.installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
- destroyInternal();
- dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Dry run", new Bundle());
+ // Staged sessions will be installed later during boot
+ if (isStaged()) {
+ // TODO(b/136257624): Remove this once all verification logic has been transferred out
+ // of StagingManager.
+ mStagingManager.notifyPreRebootVerification_Apk_Complete(sessionId);
+ // TODO(b/136257624): We also need to destroy internals for verified staged session,
+ // otherwise file descriptors are never closed for verified staged session until reboot
return;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9c8b972985eb..c05bc455887d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -367,7 +367,6 @@ import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.permission.BasePermission;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
-import com.android.server.pm.permission.PermissionsState;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.rollback.RollbackManagerInternal;
import com.android.server.security.VerityUtils;
@@ -1818,7 +1817,7 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
removeMessages(WRITE_SETTINGS);
removeMessages(WRITE_PACKAGE_RESTRICTIONS);
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
mDirtyUsers.clear();
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
@@ -1838,6 +1837,7 @@ public class PackageManagerService extends IPackageManager.Stub
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mLock) {
removeMessages(WRITE_PACKAGE_LIST);
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
mSettings.writePackageListLPr(msg.arg1);
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
@@ -2518,7 +2518,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
mSettings.onVolumeForgotten(fsUuid);
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
};
@@ -3442,6 +3442,7 @@ public class PackageManagerService extends IPackageManager.Stub
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");
+ mPermissionManager.readPermissionsStateFromPackageSettingsTEMP();
// If the platform SDK has changed since the last time we booted,
// we need to re-grant app permission to catch any new ones that
// appear. This is really a hack, and means that apps can in some
@@ -3561,7 +3562,7 @@ public class PackageManagerService extends IPackageManager.Stub
// can downgrade to reader
t.traceBegin("write settings");
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
t.traceEnd();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
@@ -3765,7 +3766,7 @@ public class PackageManagerService extends IPackageManager.Stub
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
}
mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
} catch (PackageManagerException e) {
// Whoops! Something went very wrong; roll back to the stub and disable the package
@@ -3776,9 +3777,8 @@ public class PackageManagerService extends IPackageManager.Stub
// If we don't, installing the system package fails during scan
enableSystemPackageLPw(stubPkg);
}
- installPackageFromSystemLIF(stubPkg.getCodePath(),
- null /*allUserHandles*/, null /*origUserHandles*/,
- null /*origPermissionsState*/, true /*writeSettings*/);
+ installPackageFromSystemLIF(stubPkg.getCodePath(), null /*allUserHandles*/,
+ null /*origUserHandles*/, true /*writeSettings*/);
} catch (PackageManagerException pme) {
// Serious WTF; we have to be able to install the stub
Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
@@ -3792,7 +3792,7 @@ public class PackageManagerService extends IPackageManager.Stub
stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
UserHandle.USER_SYSTEM, "android");
}
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
return false;
@@ -5806,10 +5806,6 @@ public class PackageManagerService extends IPackageManager.Stub
private void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) {
for (int i = userList.length - 1; i >= 0; --i) {
final int userId = userList[i];
- // don't add instant app to the list of updates
- if (pkgSetting.getInstantApp(userId)) {
- continue;
- }
SparseArray<String> changedPackages = mChangedPackages.get(userId);
if (changedPackages == null) {
changedPackages = new SparseArray<>();
@@ -5854,6 +5850,11 @@ public class PackageManagerService extends IPackageManager.Stub
for (int i = sequenceNumber; i < mChangedPackagesSequenceNumber; i++) {
final String packageName = changedPackages.get(i);
if (packageName != null) {
+ // Filter out the changes if the calling package should not be able to see it.
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
+ continue;
+ }
packageNames.add(packageName);
}
}
@@ -11680,8 +11681,9 @@ public class PackageManagerService extends IPackageManager.Stub
if (DEBUG_ABI_SELECTION) {
Slog.d(TAG, "Resolved nativeLibraryRoot for " + parsedPackage.getPackageName()
- + " to root=" + parsedPackage.getNativeLibraryRootDir() + ", isa="
- + parsedPackage.isNativeLibraryRootRequiresIsa());
+ + " to root=" + parsedPackage.getNativeLibraryRootDir()
+ + ", to dir=" + parsedPackage.getNativeLibraryDir()
+ + ", isa=" + parsedPackage.isNativeLibraryRootRequiresIsa());
}
// Push the derived path down into PackageSettings so we know what to
@@ -11689,9 +11691,10 @@ public class PackageManagerService extends IPackageManager.Stub
pkgSetting.legacyNativeLibraryPathString = parsedPackage.getNativeLibraryRootDir();
if (DEBUG_ABI_SELECTION) {
- Log.d(TAG, "Abis for package[" + parsedPackage.getPackageName() + "] are" +
- " primary=" + AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage) +
- " secondary=" + AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage));
+ Log.d(TAG, "Abis for package[" + parsedPackage.getPackageName() + "] are"
+ + " primary=" + pkgSetting.primaryCpuAbiString
+ + " secondary=" + pkgSetting.primaryCpuAbiString
+ + " abiOverride=" + pkgSetting.cpuAbiOverrideString);
}
if ((scanFlags & SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
@@ -13092,7 +13095,7 @@ public class PackageManagerService extends IPackageManager.Stub
return true;
}
if (sendRemoved) {
- killApplication(packageName, UserHandle.getUid(userId, pkgSetting.appId),
+ killApplication(packageName, pkgSetting.appId, userId,
"hiding pkg");
sendApplicationHiddenForUser(packageName, pkgSetting, userId);
return true;
@@ -15198,6 +15201,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
public void handleStartCopy() {
+ if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
+ // Apex packages get verified in StagingManager currently.
+ // TODO(b/136257624): Move apex verification logic out of StagingManager
+ mRet = INSTALL_SUCCEEDED;
+ return;
+ }
+
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);
@@ -16280,7 +16290,7 @@ public class PackageManagerService extends IPackageManager.Stub
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
//to update install status
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -17610,12 +17620,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null
&& pkgSetting.getPkgState().isUpdatedSystemApp();
+ final String abiOverride = deriveAbiOverride(args.abiOverride, pkgSetting);
AndroidPackage oldPackage = mPackages.get(pkgName);
boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem();
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
derivedAbi = mInjector.getAbiHelper().derivePackageAbi(parsedPackage,
isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred,
- args.abiOverride);
+ abiOverride);
derivedAbi.first.applyTo(parsedPackage);
derivedAbi.second.applyTo(parsedPackage);
} catch (PackageManagerException pme) {
@@ -18877,6 +18888,10 @@ public class PackageManagerService extends IPackageManager.Stub
if (outInfo != null) {
outInfo.removedAppId = removedAppId;
}
+ if ((deletedPs.sharedUser == null || deletedPs.sharedUser.packages.size() == 0)
+ && !isUpdatedSystemApp(deletedPs)) {
+ mPermissionManager.removePermissionsStateTEMP(removedAppId);
+ }
mPermissionManager.updatePermissions(deletedPs.name, null);
if (deletedPs.sharedUser != null) {
// Remove permissions associated with package. Since runtime
@@ -18886,10 +18901,10 @@ public class PackageManagerService extends IPackageManager.Stub
// package is successful and this causes a change in gids.
boolean shouldKill = false;
for (int userId : UserManagerService.getInstance().getUserIds()) {
- final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs,
- userId);
- shouldKill |= userIdToKill == UserHandle.USER_ALL
- || userIdToKill >= UserHandle.USER_SYSTEM;
+ final int userIdToKill = mPermissionManager
+ .revokeSharedUserPermissionsForDeletedPackageTEMP(deletedPs,
+ userId);
+ shouldKill |= userIdToKill != UserHandle.USER_NULL;
}
// If gids changed, kill all affected packages.
if (shouldKill) {
@@ -18933,7 +18948,7 @@ public class PackageManagerService extends IPackageManager.Stub
// can downgrade to reader
if (writeSettings) {
// Save settings now
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
if (installedStateChanged) {
mSettings.writeKernelMappingLPr(deletedPs);
@@ -19020,8 +19035,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
try {
installPackageFromSystemLIF(disabledPs.getCodePathString(), allUserHandles,
- outInfo == null ? null : outInfo.origUsers, deletedPs.getPermissionsState(),
- writeSettings);
+ outInfo == null ? null : outInfo.origUsers, writeSettings);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": "
+ e.getMessage());
@@ -19052,9 +19066,8 @@ public class PackageManagerService extends IPackageManager.Stub
* Installs a package that's already on the system partition.
*/
private AndroidPackage installPackageFromSystemLIF(@NonNull String codePathString,
- @Nullable int[] allUserHandles, @Nullable int[] origUserHandles,
- @Nullable PermissionsState origPermissionState, boolean writeSettings)
- throws PackageManagerException {
+ @Nullable int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings)
+ throws PackageManagerException {
final File codePath = new File(codePathString);
@ParseFlags int parseFlags =
mDefParseFlags
@@ -19091,12 +19104,8 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
- // Propagate the permissions state as we do not want to drop on the floor
- // runtime permissions. The update permissions method below will take
- // care of removing obsolete permissions and grant install permissions.
- if (origPermissionState != null) {
- ps.getPermissionsState().copyFrom(origPermissionState);
- }
+ // The update permissions method below will take care of removing obsolete permissions
+ // and granting install permissions.
mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
final boolean applyUserRestrictions
@@ -19130,7 +19139,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// can downgrade to reader here
if (writeSettings) {
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
return pkg;
@@ -19204,7 +19213,7 @@ public class PackageManagerService extends IPackageManager.Stub
} else {
ps.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER;
}
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
return true;
}
@@ -20396,7 +20405,7 @@ public class PackageManagerService extends IPackageManager.Stub
(parser1, userId1) -> {
synchronized (mLock) {
mSettings.readAllDomainVerificationsLPr(parser1, userId1);
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
});
} catch (Exception e) {
@@ -21747,6 +21756,8 @@ public class PackageManagerService extends IPackageManager.Stub
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
+
DumpState dumpState = new DumpState();
boolean fullPreferred = false;
boolean checkin = false;
@@ -21942,7 +21953,7 @@ public class PackageManagerService extends IPackageManager.Stub
dumpState.setDump(DumpState.DUMP_SERVICE_PERMISSIONS);
} else if ("write".equals(cmd)) {
synchronized (mLock) {
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
pw.println("Settings written.");
return;
}
@@ -22660,7 +22671,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Yay, everything is now upgraded
ver.forceCurrent();
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
for (PackageFreezer freezer : freezers) {
@@ -22710,7 +22721,7 @@ public class PackageManagerService extends IPackageManager.Stub
AttributeCache.instance().removePackage(ps.name);
}
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
@@ -23623,6 +23634,8 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
mDirtyUsers.remove(userId);
mUserNeedsBadging.delete(userId);
+ mPermissionManager.onUserRemoved(userId);
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
mSettings.removeUserLPw(userId);
mPendingBroadcasts.remove(userId);
mInstantAppRegistry.onUserRemovedLPw(userId);
@@ -23723,7 +23736,9 @@ public class PackageManagerService extends IPackageManager.Stub
boolean readPermissionStateForUser(@UserIdInt int userId) {
synchronized (mPackages) {
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
mSettings.readPermissionStateForUserSyncLPr(userId);
+ mPermissionManager.readPermissionsStateFromPackageSettingsTEMP();
return mPmInternal.isPermissionUpgradeNeeded(userId);
}
}
@@ -24596,12 +24611,6 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public int getPackageUid(String packageName, int flags, int userId) {
return PackageManagerService.this
- .getPackageUid(packageName, flags, userId);
- }
-
- @Override
- public int getPackageUidInternal(String packageName, int flags, int userId) {
- return PackageManagerService.this
.getPackageUidInternal(packageName, flags, userId, Process.SYSTEM_UID);
}
@@ -25179,7 +25188,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (async) {
scheduleWriteSettingsLocked();
} else {
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
}
@@ -25226,7 +25235,7 @@ public class PackageManagerService extends IPackageManager.Stub
return;
}
mSettings.mReadExternalStorageEnforced = enforced ? Boolean.TRUE : Boolean.FALSE;
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
@@ -25740,6 +25749,17 @@ public class PackageManagerService extends IPackageManager.Stub
public List<String> getMimeGroup(String packageName, String mimeGroup) {
return mSettings.mPackages.get(packageName).getMimeGroup(mimeGroup);
}
+
+ /**
+ * Temporary method that wraps mSettings.writeLPr() and calls
+ * mPermissionManager.writePermissionsStateToPackageSettingsTEMP() beforehand.
+ *
+ * TODO(zhanghai): This should be removed once we finish migration of permission storage.
+ */
+ private void writeSettingsLPrTEMP() {
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
+ mSettings.writeLPr();
+ }
}
interface PackageSender {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index de0e4b53adab..491b4fc515ce 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -34,7 +34,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.ResolveInfo;
@@ -68,7 +67,6 @@ import com.android.server.EventLogTags;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.permission.PermissionsState;
import dalvik.system.VMRuntime;
@@ -968,20 +966,6 @@ public class PackageManagerServiceUtils {
}
/**
- * Returns the {@link PermissionsState} for the given package. If the {@link PermissionsState}
- * could not be found, {@code null} will be returned.
- */
- public static PermissionsState getPermissionsState(
- PackageManagerInternal packageManagerInternal, AndroidPackage pkg) {
- final PackageSetting packageSetting = packageManagerInternal.getPackageSetting(
- pkg.getPackageName());
- if (packageSetting == null) {
- return null;
- }
- return packageSetting.getPermissionsState();
- }
-
- /**
* Recursively create target directory
*/
public static void makeDirRecursive(File targetDir, int mode) throws ErrnoException {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 32ec052a1fe0..4d2e22a2640e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -103,6 +103,7 @@ import android.util.SparseArray;
import com.android.internal.content.PackageHelper;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.pm.PackageManagerShellCommandDataLoader.Metadata;
@@ -138,7 +139,7 @@ class PackageManagerShellCommand extends ShellCommand {
private static final String STDIN_PATH = "-";
/** Path where ART profiles snapshots are dumped for the shell user */
private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/";
- private static final int DEFAULT_WAIT_MS = 60 * 1000;
+ private static final int DEFAULT_STAGED_READY_TIMEOUT_MS = 60 * 1000;
private static final String TAG = "PackageManagerShellCommand";
final IPackageManager mInterface;
@@ -463,9 +464,20 @@ class PackageManagerShellCommand extends ShellCommand {
return 1;
}
- private int runRollbackApp() {
+ private int runRollbackApp() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
+ String opt;
+ long stagedReadyTimeoutMs = DEFAULT_STAGED_READY_TIMEOUT_MS;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--staged-ready-timeout":
+ stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired());
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown option: " + opt);
+ }
+ }
final String packageName = getNextArgRequired();
if (packageName == null) {
pw.println("Error: package name not specified");
@@ -495,14 +507,21 @@ class PackageManagerShellCommand extends ShellCommand {
final Intent result = receiver.getResult();
final int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
RollbackManager.STATUS_FAILURE);
- if (status == RollbackManager.STATUS_SUCCESS) {
- pw.println("Success");
- return 0;
- } else {
+
+ if (status != RollbackManager.STATUS_SUCCESS) {
pw.println("Failure ["
+ result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE) + "]");
return 1;
}
+
+ if (rollback.isStaged() && stagedReadyTimeoutMs > 0) {
+ final int committedSessionId = rollback.getCommittedSessionId();
+ return doWaitForStagedSessionReady(committedSessionId, stagedReadyTimeoutMs, pw);
+ }
+
+ pw.println("Success");
+ return 0;
+
}
private void setParamsSize(InstallParams params, List<String> inPaths) {
@@ -1307,11 +1326,12 @@ class PackageManagerShellCommand extends ShellCommand {
}
abandonSession = false;
- if (!params.sessionParams.isStaged || !params.mWaitForStagedSessionReady) {
- pw.println("Success");
- return 0;
+ if (params.sessionParams.isStaged && params.stagedReadyTimeoutMs > 0) {
+ return doWaitForStagedSessionReady(sessionId, params.stagedReadyTimeoutMs, pw);
}
- return doWaitForStagedSessionRead(sessionId, params.timeoutMs, pw);
+
+ pw.println("Success");
+ return 0;
} finally {
if (abandonSession) {
try {
@@ -1322,11 +1342,9 @@ class PackageManagerShellCommand extends ShellCommand {
}
}
- private int doWaitForStagedSessionRead(int sessionId, long timeoutMs, PrintWriter pw)
+ private int doWaitForStagedSessionReady(int sessionId, long timeoutMs, PrintWriter pw)
throws RemoteException {
- if (timeoutMs <= 0) {
- timeoutMs = DEFAULT_WAIT_MS;
- }
+ Preconditions.checkArgument(timeoutMs > 0);
PackageInstaller.SessionInfo si = mInterface.getPackageInstaller()
.getSessionInfo(sessionId);
if (si == null) {
@@ -1376,25 +1394,14 @@ class PackageManagerShellCommand extends ShellCommand {
private int runInstallCommit() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
String opt;
- boolean waitForStagedSessionReady = true;
- long timeoutMs = -1;
+ long stagedReadyTimeoutMs = DEFAULT_STAGED_READY_TIMEOUT_MS;
while ((opt = getNextOption()) != null) {
switch (opt) {
- case "--wait-for-staged-ready":
- waitForStagedSessionReady = true;
- // If there is only one remaining argument, then it represents the sessionId, we
- // shouldn't try to parse it as timeoutMs.
- if (getRemainingArgsCount() > 1) {
- try {
- timeoutMs = Long.parseLong(peekNextArg());
- getNextArg();
- } catch (NumberFormatException ignore) {
- }
- }
- break;
- case "--no-wait":
- waitForStagedSessionReady = false;
+ case "--staged-ready-timeout":
+ stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired());
break;
+ default:
+ throw new IllegalArgumentException("Unknown option: " + opt);
}
}
final int sessionId = Integer.parseInt(getNextArg());
@@ -1403,11 +1410,11 @@ class PackageManagerShellCommand extends ShellCommand {
}
final PackageInstaller.SessionInfo si = mInterface.getPackageInstaller()
.getSessionInfo(sessionId);
- if (si == null || !si.isStaged() || !waitForStagedSessionReady) {
- pw.println("Success");
- return 0;
+ if (si != null && si.isStaged() && stagedReadyTimeoutMs > 0) {
+ return doWaitForStagedSessionReady(sessionId, stagedReadyTimeoutMs, pw);
}
- return doWaitForStagedSessionRead(sessionId, timeoutMs, pw);
+ pw.println("Success");
+ return 0;
}
private int runInstallCreate() throws RemoteException {
@@ -2738,8 +2745,7 @@ class PackageManagerShellCommand extends ShellCommand {
SessionParams sessionParams;
String installerPackageName;
int userId = UserHandle.USER_ALL;
- boolean mWaitForStagedSessionReady = true;
- long timeoutMs = DEFAULT_WAIT_MS;
+ long stagedReadyTimeoutMs = DEFAULT_STAGED_READY_TIMEOUT_MS;
}
private InstallParams makeInstallParams() {
@@ -2868,16 +2874,8 @@ class PackageManagerShellCommand extends ShellCommand {
}
sessionParams.installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
break;
- case "--wait-for-staged-ready":
- params.mWaitForStagedSessionReady = true;
- try {
- params.timeoutMs = Long.parseLong(peekNextArg());
- getNextArg();
- } catch (NumberFormatException ignore) {
- }
- break;
- case "--no-wait":
- params.mWaitForStagedSessionReady = false;
+ case "--staged-ready-timeout":
+ params.stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired());
break;
case "--skip-verification":
sessionParams.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
@@ -3199,12 +3197,24 @@ class PackageManagerShellCommand extends ShellCommand {
return 0;
}
+ private long getFileStatSize(File file) {
+ final ParcelFileDescriptor pfd = openFileForSystem(file.getPath(), "r");
+ if (pfd == null) {
+ throw new IllegalArgumentException("Error: Can't open file: " + file.getPath());
+ }
+ try {
+ return pfd.getStatSize();
+ } finally {
+ IoUtils.closeQuietly(pfd);
+ }
+ }
+
private void processArgForLocalFile(String arg, PackageInstaller.Session session) {
final String inPath = arg;
final File file = new File(inPath);
final String name = file.getName();
- final long size = file.length();
+ final long size = getFileStatSize(file);
final Metadata metadata = Metadata.forLocalFile(inPath);
byte[] v4signatureBytes = null;
@@ -3601,7 +3611,7 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" [--preload] [--instant] [--full] [--dont-kill]");
pw.println(" [--enable-rollback]");
pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
- pw.println(" [--apex] [--wait-for-staged-ready TIMEOUT]");
+ pw.println(" [--apex] [--staged-ready-timeout TIMEOUT]");
pw.println(" [PATH [SPLIT...]|-]");
pw.println(" Install an application. Must provide the apk data to install, either as");
pw.println(" file path(s) or '-' to read from stdin. Options are:");
@@ -3629,9 +3639,11 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" 3=device setup, 4=user request");
pw.println(" --force-uuid: force install on to disk volume with given UUID");
pw.println(" --apex: install an .apex file, not an .apk");
- pw.println(" --wait-for-staged-ready: when performing staged install, wait TIMEOUT");
- pw.println(" ms for pre-reboot verification to complete. If TIMEOUT is not");
- pw.println(" specified it will wait for " + DEFAULT_WAIT_MS + " milliseconds.");
+ pw.println(" --staged-ready-timeout: By default, staged sessions wait "
+ + DEFAULT_STAGED_READY_TIMEOUT_MS);
+ pw.println(" milliseconds for pre-reboot verification to complete when");
+ pw.println(" performing staged install. This flag is used to alter the waiting");
+ pw.println(" time. You can skip the waiting time by specifying a TIMEOUT of '0'");
pw.println("");
pw.println(" install-existing [--user USER_ID|all|current]");
pw.println(" [--instant] [--full] [--wait] [--restrict-permissions] PACKAGE");
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index acb149b9ec3d..659e2a32e267 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -955,93 +955,6 @@ public final class Settings {
}
}
- /*
- * Update the shared user setting when a package with a shared user id is removed. The gids
- * associated with each permission of the deleted package are removed from the shared user'
- * gid list only if its not in use by other permissions of packages in the shared user setting.
- *
- * @return the affected user id
- */
- @UserIdInt
- int updateSharedUserPermsLPw(PackageSetting deletedPs, int userId) {
- if ((deletedPs == null) || (deletedPs.pkg == null)) {
- Slog.i(PackageManagerService.TAG,
- "Trying to update info for null package. Just ignoring");
- return UserHandle.USER_NULL;
- }
-
- // No sharedUserId
- if (deletedPs.sharedUser == null) {
- return UserHandle.USER_NULL;
- }
-
- SharedUserSetting sus = deletedPs.sharedUser;
-
- int affectedUserId = UserHandle.USER_NULL;
- // Update permissions
- for (String eachPerm : deletedPs.pkg.getRequestedPermissions()) {
- BasePermission bp = mPermissions.getPermission(eachPerm);
- if (bp == null) {
- continue;
- }
-
- // Check if another package in the shared user needs the permission.
- boolean used = false;
- for (PackageSetting pkg : sus.packages) {
- if (pkg.pkg != null
- && !pkg.pkg.getPackageName().equals(deletedPs.pkg.getPackageName())
- && pkg.pkg.getRequestedPermissions().contains(eachPerm)) {
- used = true;
- break;
- }
- }
- if (used) {
- continue;
- }
-
- PermissionsState permissionsState = sus.getPermissionsState();
- PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.getPackageName());
-
- // If the package is shadowing is a disabled system package,
- // do not drop permissions that the shadowed package requests.
- if (disabledPs != null) {
- boolean reqByDisabledSysPkg = false;
- for (String permission : disabledPs.pkg.getRequestedPermissions()) {
- if (permission.equals(eachPerm)) {
- reqByDisabledSysPkg = true;
- break;
- }
- }
- if (reqByDisabledSysPkg) {
- continue;
- }
- }
-
- // Try to revoke as an install permission which is for all users.
- // The package is gone - no need to keep flags for applying policy.
- permissionsState.updatePermissionFlags(bp, userId,
- PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
-
- if (permissionsState.revokeInstallPermission(bp) ==
- PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
- affectedUserId = UserHandle.USER_ALL;
- }
-
- // Try to revoke as an install permission which is per user.
- if (permissionsState.revokeRuntimePermission(bp, userId) ==
- PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
- if (affectedUserId == UserHandle.USER_NULL) {
- affectedUserId = userId;
- } else if (affectedUserId != userId) {
- // Multiple users affected.
- affectedUserId = UserHandle.USER_ALL;
- }
- }
- }
-
- return affectedUserId;
- }
-
int removePackageLPw(String name) {
final PackageSetting p = mPackages.get(name);
if (p != null) {
@@ -4638,6 +4551,7 @@ public final class Settings {
? "true" : "false");
pw.print(prefix); pw.print(" primaryCpuAbi="); pw.println(ps.primaryCpuAbiString);
pw.print(prefix); pw.print(" secondaryCpuAbi="); pw.println(ps.secondaryCpuAbiString);
+ pw.print(prefix); pw.print(" cpuAbiOverride="); pw.println(ps.cpuAbiOverrideString);
}
pw.print(prefix); pw.print(" versionCode="); pw.print(ps.versionCode);
if (pkg != null) {
@@ -5533,32 +5447,11 @@ public final class Settings {
// Make sure we do not
mHandler.removeMessages(userId);
- for (SettingBase sb : mPackages.values()) {
- revokeRuntimePermissionsAndClearFlags(sb, userId);
- }
-
- for (SettingBase sb : mSharedUsers.values()) {
- revokeRuntimePermissionsAndClearFlags(sb, userId);
- }
-
mPermissionUpgradeNeeded.delete(userId);
mVersions.delete(userId);
mFingerprints.remove(userId);
}
- private void revokeRuntimePermissionsAndClearFlags(SettingBase sb, int userId) {
- PermissionsState permissionsState = sb.getPermissionsState();
- for (PermissionState permissionState
- : permissionsState.getRuntimePermissionStates(userId)) {
- BasePermission bp = mPermissions.getPermission(permissionState.getName());
- if (bp != null) {
- permissionsState.revokeRuntimePermission(bp, userId);
- permissionsState.updatePermissionFlags(bp, userId,
- PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
- }
- }
- }
-
public void deleteUserRuntimePermissionsFile(int userId) {
mPersistence.deleteForUser(UserHandle.of(userId));
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 700f7be83e15..8412077d9a11 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -3301,7 +3301,7 @@ public class ShortcutService extends IShortcutService.Stub {
final long token = Binder.clearCallingIdentity();
try {
- int packageUid = mPackageManagerInternal.getPackageUidInternal(packageName,
+ int packageUid = mPackageManagerInternal.getPackageUid(packageName,
PackageManager.MATCH_DIRECT_BOOT_AUTO, userId);
// Grant read uri permission to the caller on behalf of the shortcut owner. All
// granted permissions are revoked when the default launcher changes, or when
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 6d80f08ecbf6..0c4eaec32ba5 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -88,7 +88,6 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
@@ -189,7 +188,6 @@ public class StagingManager {
* Validates the signature used to sign the container of the new apex package
*
* @param newApexPkg The new apex package that is being installed
- * @throws PackageManagerException
*/
private void validateApexSignature(PackageInfo newApexPkg)
throws PackageManagerException {
@@ -725,12 +723,9 @@ public class StagingManager {
return ret;
}
- @NonNull
private PackageInstallerSession createAndWriteApkSession(
- @NonNull PackageInstallerSession originalSession, boolean preReboot)
- throws PackageManagerException {
- final int errorCode = preReboot ? SessionInfo.STAGED_SESSION_VERIFICATION_FAILED
- : SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
+ PackageInstallerSession originalSession) throws PackageManagerException {
+ final int errorCode = SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
if (originalSession.stageDir == null) {
Slog.wtf(TAG, "Attempting to install a staged APK session with no staging dir");
throw new PackageManagerException(errorCode,
@@ -746,12 +741,7 @@ public class StagingManager {
PackageInstaller.SessionParams params = originalSession.params.copy();
params.isStaged = false;
params.installFlags |= PackageManager.INSTALL_STAGED;
- if (preReboot) {
- params.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
- params.installFlags |= PackageManager.INSTALL_DRY_RUN;
- } else {
- params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
- }
+ params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
try {
int apkSessionId = mPi.createSession(
params, originalSession.getInstallerPackageName(),
@@ -783,12 +773,10 @@ public class StagingManager {
* apks in the given session. Only parent session is returned for multi-package session.
*/
@Nullable
- private PackageInstallerSession extractApksInSession(PackageInstallerSession session,
- boolean preReboot) throws PackageManagerException {
- final int errorCode = preReboot ? SessionInfo.STAGED_SESSION_VERIFICATION_FAILED
- : SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
+ private PackageInstallerSession extractApksInSession(PackageInstallerSession session)
+ throws PackageManagerException {
if (!session.isMultiPackage() && !isApexSession(session)) {
- return createAndWriteApkSession(session, preReboot);
+ return createAndWriteApkSession(session);
} else if (session.isMultiPackage()) {
// For multi-package staged sessions containing APKs, we identify which child sessions
// contain an APK, and with those then create a new multi-package group of sessions,
@@ -810,10 +798,6 @@ public class StagingManager {
}
final PackageInstaller.SessionParams params = session.params.copy();
params.isStaged = false;
- if (preReboot) {
- params.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
- params.installFlags |= PackageManager.INSTALL_DRY_RUN;
- }
final int apkParentSessionId = mPi.createSession(
params, session.getInstallerPackageName(), session.getInstallerAttributionTag(),
session.userId);
@@ -823,18 +807,18 @@ public class StagingManager {
} catch (IOException e) {
Slog.e(TAG, "Unable to prepare multi-package session for staged session "
+ session.sessionId);
- throw new PackageManagerException(errorCode,
+ throw new PackageManagerException(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
"Unable to prepare multi-package session for staged session");
}
for (int i = 0, size = childSessions.size(); i < size; i++) {
final PackageInstallerSession apkChildSession = createAndWriteApkSession(
- childSessions.get(i), preReboot);
+ childSessions.get(i));
try {
apkParentSession.addChildSessionId(apkChildSession.sessionId);
} catch (IllegalStateException e) {
Slog.e(TAG, "Failed to add a child session for installing the APK files", e);
- throw new PackageManagerException(errorCode,
+ throw new PackageManagerException(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
"Failed to add a child session " + apkChildSession.sessionId);
}
}
@@ -877,11 +861,9 @@ public class StagingManager {
}
}
- private void installApksInSession(@NonNull PackageInstallerSession session)
+ private void installApksInSession(PackageInstallerSession session)
throws PackageManagerException {
-
- final PackageInstallerSession apksToInstall = extractApksInSession(
- session, /* preReboot */ false);
+ final PackageInstallerSession apksToInstall = extractApksInSession(session);
if (apksToInstall == null) {
return;
}
@@ -1005,7 +987,7 @@ public class StagingManager {
// will be deleted.
}
root.setStagedSessionFailed(
- SessionInfo.STAGED_SESSION_OTHER_ERROR,
+ SessionInfo.STAGED_SESSION_CONFLICT,
"Session was blocking rollback session: " + session.sessionId);
Slog.i(TAG, "Session " + root.sessionId + " is marked failed due to "
+ "blocking rollback session: " + session.sessionId);
@@ -1047,7 +1029,7 @@ public class StagingManager {
/**
* <p>Abort committed staged session
*
- * <p>This method must be called while holding {@link PackageInstallerSession.mLock}.
+ * <p>This method must be called while holding {@link PackageInstallerSession#mLock}.
*
* <p>The method returns {@code false} to indicate it is not safe to clean up the session from
* system yet. When it is safe, the method returns {@code true}.
@@ -1218,7 +1200,7 @@ public class StagingManager {
}
}
- void markStagedSessionsAsSuccessful() {
+ private void markStagedSessionsAsSuccessful() {
synchronized (mSuccessfulStagedSessionIds) {
for (int i = 0; i < mSuccessfulStagedSessionIds.size(); i++) {
mApexManager.markStagedSessionSuccessful(mSuccessfulStagedSessionIds.get(i));
@@ -1242,30 +1224,10 @@ public class StagingManager {
mFailureReasonFile.delete();
}
- private static class LocalIntentReceiverAsync {
- final Consumer<Intent> mConsumer;
-
- LocalIntentReceiverAsync(Consumer<Intent> consumer) {
- mConsumer = consumer;
- }
-
- private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
- @Override
- public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
- IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
- mConsumer.accept(intent);
- }
- };
-
- public IntentSender getIntentSender() {
- return new IntentSender((IIntentSender) mLocalSender);
- }
- }
-
private static class LocalIntentReceiverSync {
private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>();
- private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
+ private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
@Override
public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
IIntentReceiver finishedReceiver, String requiredPermission,
@@ -1299,6 +1261,20 @@ public class StagingManager {
return session;
}
+ // TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all
+ // verification logic is extracted out of StagingManager into PMS, we can remove
+ // this.
+ void notifyVerificationComplete(int sessionId) {
+ mPreRebootVerificationHandler.onPreRebootVerificationComplete(sessionId);
+ }
+
+ // TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all
+ // verification logic is extracted out of StagingManager into PMS, we can remove
+ // this.
+ void notifyPreRebootVerification_Apk_Complete(int sessionId) {
+ mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(sessionId);
+ }
+
private final class PreRebootVerificationHandler extends Handler {
// Hold session ids before handler gets ready to do the verification.
private IntArray mPendingSessionIds;
@@ -1500,54 +1476,16 @@ public class StagingManager {
}
/**
- * Pre-reboot verification state for apk files:
- * <p><ul>
- * <li>performs a dry-run install of apk</li>
- * </ul></p>
+ * Pre-reboot verification state for apk files. Session is sent to
+ * {@link PackageManagerService} for verification and it notifies back the result via
+ * {@link #notifyPreRebootVerification_Apk_Complete(int)}
*/
private void handlePreRebootVerification_Apk(@NonNull PackageInstallerSession session) {
if (!sessionContainsApk(session)) {
notifyPreRebootVerification_Apk_Complete(session.sessionId);
return;
}
-
- try {
- Slog.d(TAG, "Running a pre-reboot verification for APKs in session "
- + session.sessionId + " by performing a dry-run install");
- // verifyApksInSession will notify the handler when APK verification is complete
- verifyApksInSession(session);
- } catch (PackageManagerException e) {
- onPreRebootVerificationFailure(session, e.error, e.getMessage());
- }
- }
-
- private void verifyApksInSession(PackageInstallerSession session)
- throws PackageManagerException {
-
- final PackageInstallerSession apksToVerify = extractApksInSession(
- session, /* preReboot */ true);
- if (apksToVerify == null) {
- return;
- }
-
- final LocalIntentReceiverAsync receiver = new LocalIntentReceiverAsync(
- (Intent result) -> {
- final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
- if (status != PackageInstaller.STATUS_SUCCESS) {
- final String errorMessage = result.getStringExtra(
- PackageInstaller.EXTRA_STATUS_MESSAGE);
- Slog.e(TAG, "Failure to verify APK staged session "
- + session.sessionId + " [" + errorMessage + "]");
- onPreRebootVerificationFailure(session,
- SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMessage);
- return;
- }
- mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(
- session.sessionId);
- });
-
- apksToVerify.commit(receiver.getIntentSender(), false);
+ session.verifyStagedSession();
}
/**
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d137fd05f793..c1aebd33889c 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -84,6 +84,7 @@ import android.os.storage.StorageManager;
import android.security.GateKeeper;
import android.service.gatekeeper.IGateKeeperService;
import android.stats.devicepolicy.DevicePolicyEnums;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -141,7 +142,6 @@ import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* Service for {@link UserManager}.
@@ -159,6 +159,10 @@ public class UserManagerService extends IUserManager.Stub {
private static final String LOG_TAG = "UserManagerService";
static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
private static final boolean DBG_WITH_STACKTRACE = false; // DO NOT SUBMIT WITH TRUE
+
+ // TODO(b/164159026): remove once owner_name issue on automotive is fixed
+ // Can be used to track getUsers() / userWithNameLU() behavior
+ public static final boolean DBG_CACHED_USERINFOS = false; // DO NOT SUBMIT WITH TRUE
// Can be used for manual testing of id recycling
private static final boolean RELEASE_DELETED_USER_ID = false; // DO NOT SUBMIT WITH TRUE
@@ -272,6 +276,25 @@ public class UserManagerService extends IUserManager.Stub {
private DevicePolicyManagerInternal mDevicePolicyManagerInternal;
/**
+ * Reference to the {@link UserHandle#SYSTEM} user's UserInfo; it's {@code name} was either
+ * manually set, or it's {@code null}.
+ *
+ * <p>The reference is set just once, but it's {@code name} is updated when it's manually set.
+ */
+ @GuardedBy("mUsersLock")
+ private UserInfo mSystemUserInfo;
+
+ /**
+ * Reference to the {@link UserHandle#SYSTEM} user's UserInfo, with its {@code name} set to
+ * the localized value of {@code owner_name}.
+ *
+ * <p>The reference is set just once, but it's {@code name} is updated everytime the reference
+ * is used and the locale changed.
+ */
+ @GuardedBy("mUsersLock")
+ private UserInfo mSystemUserInfoWithName;
+
+ /**
* Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps.
*/
@VisibleForTesting
@@ -444,11 +467,6 @@ public class UserManagerService extends IUserManager.Stub {
}
};
- // TODO(b/161915546): remove once userWithName() is fixed / removed
- // Use to debug / dump when user 0 is allocated at userWithName()
- public static final boolean DBG_ALLOCATION = false; // DO NOT SUBMIT WITH TRUE
- public final AtomicInteger mUser0Allocations;
-
/**
* Start an {@link IntentSender} when user is unlocked after disabling quiet mode.
*
@@ -638,7 +656,6 @@ public class UserManagerService extends IUserManager.Stub {
LocalServices.addService(UserManagerInternal.class, mLocalService);
mLockPatternUtils = new LockPatternUtils(mContext);
mUserStates.put(UserHandle.USER_SYSTEM, UserState.STATE_BOOTING);
- mUser0Allocations = DBG_ALLOCATION ? new AtomicInteger() : null;
}
void systemReady() {
@@ -784,7 +801,7 @@ public class UserManagerService extends IUserManager.Stub {
|| (excludePreCreated && ui.preCreated)) {
continue;
}
- users.add(userWithName(ui));
+ users.add(userWithNameLU(ui));
}
return users;
}
@@ -853,7 +870,7 @@ public class UserManagerService extends IUserManager.Stub {
userInfo.name = null;
userInfo.iconPath = null;
} else {
- userInfo = userWithName(userInfo);
+ userInfo = userWithNameLU(userInfo);
}
users.add(userInfo);
}
@@ -1310,26 +1327,57 @@ public class UserManagerService extends IUserManager.Stub {
public UserInfo getUserInfo(@UserIdInt int userId) {
checkManageOrCreateUsersPermission("query user");
synchronized (mUsersLock) {
- return userWithName(getUserInfoLU(userId));
+ return userWithNameLU(getUserInfoLU(userId));
}
}
/**
* Returns a UserInfo object with the name filled in, for Owner, or the original
* if the name is already set.
+ *
+ * <p>Note:</p> the Owner name is localized, so the current value must be checked every time
+ * this method is called.
*/
- private UserInfo userWithName(UserInfo orig) {
- if (orig != null && orig.name == null && orig.id == UserHandle.USER_SYSTEM) {
- if (DBG_ALLOCATION) {
- final int number = mUser0Allocations.incrementAndGet();
- Slog.w(LOG_TAG, "System user instantiated at least " + number + " times");
- }
- UserInfo withName = new UserInfo(orig);
- withName.name = getOwnerName();
- return withName;
- } else {
- return orig;
+ private UserInfo userWithNameLU(UserInfo orig) {
+ // Only the system user uses the owner_name string.
+ if (orig == null || orig.id != UserHandle.USER_SYSTEM) return orig;
+
+ if (mSystemUserInfo == null) {
+ mSystemUserInfo = orig;
+ if (DBG_CACHED_USERINFOS) {
+ Slog.d(LOG_TAG, "Set mSystemUserInfo:" + mSystemUserInfo.toFullString());
+ }
}
+
+ if (mSystemUserInfo.name != null) {
+ if (DBG_CACHED_USERINFOS) {
+ Slog.v(LOG_TAG, "Returning mSystemUserInfo: " + mSystemUserInfo.toFullString());
+ }
+ return mSystemUserInfo;
+ }
+
+ final String ownerName = getOwnerName();
+
+ if (mSystemUserInfoWithName == null) {
+ mSystemUserInfoWithName = new UserInfo(orig);
+ mSystemUserInfoWithName.name = ownerName;
+ if (DBG_CACHED_USERINFOS) {
+ Slog.d(LOG_TAG, "Set mSystemUserInfoWithName: "
+ + mSystemUserInfoWithName.toFullString());
+ }
+ } else if (!TextUtils.equals(ownerName, mSystemUserInfoWithName.name)) {
+ if (DBG_CACHED_USERINFOS) {
+ Slog.d(LOG_TAG, "Updating mSystemUserInfoWithName.name from "
+ + mSystemUserInfoWithName.name + " to " + ownerName);
+ }
+ mSystemUserInfoWithName.name = ownerName;
+ }
+
+ if (DBG_CACHED_USERINFOS) {
+ Slog.v(LOG_TAG, "Returning mSystemUserInfoWithName:"
+ + mSystemUserInfoWithName.toFullString());
+ }
+ return mSystemUserInfoWithName;
}
/** Returns whether the given user type is one of the FULL user types. */
@@ -1482,7 +1530,7 @@ public class UserManagerService extends IUserManager.Stub {
}
final int userId = UserHandle.getUserId(Binder.getCallingUid());
synchronized (mUsersLock) {
- UserInfo userInfo = userWithName(getUserInfoLU(userId));
+ UserInfo userInfo = userWithNameLU(getUserInfoLU(userId));
return userInfo == null ? "" : userInfo.name;
}
}
@@ -1597,6 +1645,13 @@ public class UserManagerService extends IUserManager.Stub {
Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId);
return null;
}
+
+ if (DBG_CACHED_USERINFOS && userId == UserHandle.USER_SYSTEM && userData != null
+ && userData.info != mSystemUserInfo) {
+ Slog.wtf(LOG_TAG, "getUserInfoLU(): system user on userData (" + userData.info
+ + ") is not the same as mSystemUserInfo (" + mSystemUserInfo + ")");
+ }
+
return userData != null ? userData.info : null;
}
@@ -4855,8 +4910,15 @@ public class UserManagerService extends IUserManager.Stub {
pw.println(" Is headless-system mode: " + UserManager.isHeadlessSystemUserMode());
pw.println(" User version: " + mUserVersion);
pw.println(" Owner name: " + getOwnerName());
- if (DBG_ALLOCATION) {
- pw.println(" System user allocations: " + mUser0Allocations.get());
+ if (mSystemUserInfo == null) {
+ pw.println(" (mSystemUserInfo not set)");
+ } else {
+ pw.println(" System user: " + mSystemUserInfo.toFullString());
+ }
+ if (mSystemUserInfoWithName == null) {
+ pw.println(" (mSystemUserInfoWithName not set)");
+ } else {
+ pw.println(" System user (with name): " + mSystemUserInfoWithName.toFullString());
}
// Dump UserTypes
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index cfa0449aaf33..962638b4f63c 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -38,7 +38,6 @@ import android.util.Slog;
import com.android.server.pm.DumpState;
import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.PackageSetting;
import com.android.server.pm.PackageSettingBase;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -420,8 +419,7 @@ public final class BasePermission {
}
public void enforceDeclaredUsedAndRuntimeOrDevelopment(AndroidPackage pkg,
- PackageSetting pkgSetting) {
- final PermissionsState permsState = pkgSetting.getPermissionsState();
+ PermissionsState permsState) {
int index = pkg.getRequestedPermissions().indexOf(name);
if (!permsState.hasRequestedPermission(name) && index == -1) {
throw new SecurityException("Package " + pkg.getPackageName()
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 1be74154b53a..f5dd918a18f3 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -162,6 +162,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -227,6 +228,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
/** Internal connection to the user manager */
private final UserManagerInternal mUserManagerInt;
+ /** Maps from App ID to PermissionsState */
+ private final SparseArray<PermissionsState> mAppIdStates = new SparseArray<>();
+
/** Permission controller: User space permission management */
private PermissionControllerManager mPermissionControllerManager;
@@ -671,11 +675,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (pkg == null) {
return 0;
}
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
- return 0;
- }
synchronized (mLock) {
if (mSettings.getPermissionLocked(permName) == null) {
return 0;
@@ -684,7 +683,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
return 0;
}
- PermissionsState permissionsState = ps.getPermissionsState();
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
+ return 0;
+ }
return permissionsState.getPermissionFlags(permName, userId);
}
@@ -771,9 +774,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- packageName);
- if (pkg == null || ps == null) {
+ if (pkg == null) {
Log.e(TAG, "Unknown package: " + packageName);
return;
}
@@ -789,7 +790,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
throw new IllegalArgumentException("Unknown permission: " + permName);
}
- final PermissionsState permissionsState = ps.getPermissionsState();
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
+ return;
+ }
+
final boolean hadState =
permissionsState.getRuntimePermissionState(permName, userId) != null;
if (!hadState) {
@@ -864,12 +870,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final boolean[] changed = new boolean[1];
mPackageManagerInt.forEachPackage(pkg -> {
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions(
userId, effectiveFlagMask, effectiveFlagValues);
mOnPermissionChangeListeners.onPermissionsChanged(pkg.getUid());
@@ -923,12 +928,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
final int uid = UserHandle.getUid(userId, pkg.getUid());
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return PackageManager.PERMISSION_DENIED;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
if (checkSinglePermissionInternal(uid, permissionsState, permissionName)) {
return PackageManager.PERMISSION_GRANTED;
@@ -1139,9 +1143,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final long identity = Binder.clearCallingIdentity();
try {
- final PermissionsState permissionsState =
- PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
return null;
}
@@ -1451,7 +1455,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
+ return;
+ }
+
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, permissionsState);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
@@ -1464,8 +1474,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid()));
- final PermissionsState permissionsState = ps.getPermissionsState();
-
final int flags = permissionsState.getPermissionFlags(permName, userId);
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
Log.e(TAG, "Cannot grant system fixed permission "
@@ -1599,9 +1607,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
"revokeRuntimePermission");
final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- packageName);
- if (pkg == null || ps == null) {
+ if (pkg == null) {
Log.e(TAG, "Unknown package: " + packageName);
return;
}
@@ -1613,7 +1619,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
throw new IllegalArgumentException("Unknown permission: " + permName);
}
- bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
+ return;
+ }
+
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, permissionsState);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
@@ -1624,8 +1636,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
-
final int flags = permissionsState.getPermissionFlags(permName, userId);
// Only the system may revoke SYSTEM_FIXED permissions.
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0
@@ -2456,14 +2466,36 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
+ private void onUserRemoved(@UserIdInt int userId) {
+ synchronized (mLock) {
+ final int appIdStatesSize = mAppIdStates.size();
+ for (int i = 0; i < appIdStatesSize; i++) {
+ PermissionsState permissionsState = mAppIdStates.valueAt(i);
+ for (PermissionState permissionState
+ : permissionsState.getRuntimePermissionStates(userId)) {
+ BasePermission bp = mSettings.getPermission(permissionState.getName());
+ if (bp != null) {
+ permissionsState.revokeRuntimePermission(bp, userId);
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
+ }
+ }
+ }
+ }
+ }
+
@NonNull
private Set<String> getGrantedPermissions(@NonNull String packageName,
@UserIdInt int userId) {
final PackageSetting ps = mPackageManagerInt.getPackageSetting(packageName);
if (ps == null) {
- return null;
+ return Collections.emptySet();
+ }
+ final PermissionsState permissionsState = getPermissionsState(ps);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
+ return Collections.emptySet();
}
- final PermissionsState permissionsState = ps.getPermissionsState();
if (!ps.getInstantApp(userId)) {
return permissionsState.getPermissions(userId);
} else {
@@ -2503,7 +2535,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (ps == null) {
return null;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
+ final PermissionsState permissionsState = getPermissionsState(ps);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
+ return null;
+ }
return permissionsState.computeGids(userId);
}
@@ -2541,8 +2577,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (ps == null) {
return;
}
-
- final PermissionsState permissionsState = ps.getPermissionsState();
+ final PermissionsState permissionsState = getOrCreatePermissionsState(ps);
final int[] userIds = getAllUserIds();
@@ -2614,8 +2649,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// changed runtime permissions here are promotion of an install to
// runtime and revocation of a runtime from a shared user.
synchronized (mLock) {
- updatedUserIds = revokeUnusedSharedUserPermissionsLocked(ps.getSharedUser(),
- userIds);
+ updatedUserIds = revokeUnusedSharedUserPermissionsLocked(
+ ps.getSharedUser().getPackages(), permissionsState, userIds);
if (!ArrayUtils.isEmpty(updatedUserIds)) {
runtimePermissionsRevoked = true;
}
@@ -3091,6 +3126,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
updatedUserIds);
}
+ // TODO: Kill UIDs whose GIDs or runtime permissions changed. This might be more important
+ // for shared users.
// Persist the runtime permissions state for users with changes. If permissions
// were revoked because no app in the shared user declares them we have to
// write synchronously to avoid losing runtime permissions state.
@@ -3554,37 +3591,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final PackageSetting disabledPs = mPackageManagerInt
.getDisabledSystemPackage(pkg.getPackageName());
final AndroidPackage disabledPkg = disabledPs == null ? null : disabledPs.pkg;
- if (disabledPs != null
- && disabledPs.getPermissionsState().hasInstallPermission(perm)) {
- // If the original was granted this permission, we take
- // that grant decision as read and propagate it to the
- // update.
- if ((privilegedPermission && disabledPs.isPrivileged())
- || (oemPermission && disabledPs.isOem()
- && canGrantOemPermission(disabledPs, perm))) {
- allowed = true;
- }
- } else {
- // The system apk may have been updated with an older
- // version of the one on the data partition, but which
- // granted a new system permission that it didn't have
- // before. In this case we do want to allow the app to
- // now get the new permission if the ancestral apk is
- // privileged to get it.
- if (disabledPs != null && disabledPkg != null
- && isPackageRequestingPermission(disabledPkg, perm)
- && ((privilegedPermission && disabledPs.isPrivileged())
- || (oemPermission && disabledPs.isOem()
- && canGrantOemPermission(disabledPs, perm)))) {
- allowed = true;
- }
+ if (disabledPkg != null && isPackageRequestingPermission(disabledPkg, perm)
+ && ((privilegedPermission && disabledPkg.isPrivileged())
+ || (oemPermission && canGrantOemPermission(disabledPkg,
+ perm)))) {
+ allowed = true;
}
} else {
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
allowed = (privilegedPermission && pkg.isPrivileged())
- || (oemPermission && pkg.isOem()
- && canGrantOemPermission(ps, perm));
+ || (oemPermission && canGrantOemPermission(pkg, perm));
}
// In any case, don't grant a privileged permission to privileged vendor apps, if
// the permission's protectionLevel does not have the extra 'vendorPrivileged'
@@ -3735,16 +3750,16 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return false;
}
- private static boolean canGrantOemPermission(PackageSetting ps, String permission) {
- if (!ps.isOem()) {
+ private static boolean canGrantOemPermission(AndroidPackage pkg, String permission) {
+ if (!pkg.isOem()) {
return false;
}
// all oem permissions must explicitly be granted or denied
final Boolean granted =
- SystemConfig.getInstance().getOemPermissions(ps.name).get(permission);
+ SystemConfig.getInstance().getOemPermissions(pkg.getPackageName()).get(permission);
if (granted == null) {
throw new IllegalStateException("OEM permission" + permission + " requested by package "
- + ps.name + " must be explicitly declared granted or not");
+ + pkg.getPackageName() + " must be explicitly declared granted or not");
}
return Boolean.TRUE == granted;
}
@@ -3757,12 +3772,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
// Legacy apps have the permission and get user consent on launch.
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return false;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
return permissionsState.isPermissionReviewRequired(userId);
}
@@ -3787,14 +3801,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private void grantRequestedRuntimePermissionsForUser(AndroidPackage pkg, int userId,
String[] grantedPermissions, int callingUid, PermissionCallback callback) {
- PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return;
}
- PermissionsState permissionsState = ps.getPermissionsState();
-
final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
| PackageManager.FLAG_PERMISSION_POLICY_FIXED;
@@ -3838,9 +3850,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private void setWhitelistedRestrictedPermissionsForUsers(@NonNull AndroidPackage pkg,
@UserIdInt int[] userIds, @Nullable List<String> permissions, int callingUid,
@PermissionWhitelistFlags int whitelistFlags, PermissionCallback callback) {
- final PermissionsState permissionsState =
- PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return;
}
@@ -3958,9 +3970,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
for (int j = 0; j < oldGrantedCount; j++) {
final String permission = oldPermsForUser.valueAt(j);
// Sometimes we create a new permission state instance during update.
- final PermissionsState newPermissionsState =
- PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt,
- pkg);
+ final PermissionsState newPermissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
+ continue;
+ }
if (!newPermissionsState.hasPermission(permission, userId)) {
callback.onPermissionRevoked(pkg.getUid(), userId, null);
break;
@@ -3970,12 +3984,100 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
+ @UserIdInt
+ private int revokeSharedUserPermissionsForDeletedPackage(@NonNull PackageSetting deletedPs,
+ @UserIdInt int userId) {
+ if ((deletedPs == null) || (deletedPs.pkg == null)) {
+ Slog.i(TAG, "Trying to update info for null package. Just ignoring");
+ return UserHandle.USER_NULL;
+ }
+
+ SharedUserSetting sus = deletedPs.getSharedUser();
+
+ // No sharedUserId
+ if (sus == null) {
+ return UserHandle.USER_NULL;
+ }
+
+ int affectedUserId = UserHandle.USER_NULL;
+ // Update permissions
+ for (String eachPerm : deletedPs.pkg.getRequestedPermissions()) {
+ BasePermission bp = mSettings.getPermission(eachPerm);
+ if (bp == null) {
+ continue;
+ }
+
+ // Check if another package in the shared user needs the permission.
+ boolean used = false;
+ final List<AndroidPackage> pkgs = sus.getPackages();
+ if (pkgs != null) {
+ for (AndroidPackage pkg : pkgs) {
+ if (pkg != null
+ && !pkg.getPackageName().equals(deletedPs.pkg.getPackageName())
+ && pkg.getRequestedPermissions().contains(eachPerm)) {
+ used = true;
+ break;
+ }
+ }
+ }
+ if (used) {
+ continue;
+ }
+
+ PermissionsState permissionsState = getPermissionsState(deletedPs.pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + deletedPs.pkg.getPackageName());
+ continue;
+ }
+
+ PackageSetting disabledPs = mPackageManagerInt.getDisabledSystemPackage(
+ deletedPs.pkg.getPackageName());
+
+ // If the package is shadowing is a disabled system package,
+ // do not drop permissions that the shadowed package requests.
+ if (disabledPs != null) {
+ boolean reqByDisabledSysPkg = false;
+ for (String permission : disabledPs.pkg.getRequestedPermissions()) {
+ if (permission.equals(eachPerm)) {
+ reqByDisabledSysPkg = true;
+ break;
+ }
+ }
+ if (reqByDisabledSysPkg) {
+ continue;
+ }
+ }
+
+ // Try to revoke as an install permission which is for all users.
+ // The package is gone - no need to keep flags for applying policy.
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
+
+ if (permissionsState.revokeInstallPermission(bp)
+ == PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
+ affectedUserId = UserHandle.USER_ALL;
+ }
+
+ // Try to revoke as a runtime permission which is per user.
+ if (permissionsState.revokeRuntimePermission(bp, userId)
+ == PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
+ if (affectedUserId == UserHandle.USER_NULL) {
+ affectedUserId = userId;
+ } else if (affectedUserId != userId) {
+ // Multiple users affected.
+ affectedUserId = UserHandle.USER_ALL;
+ }
+ }
+ }
+
+ return affectedUserId;
+ }
+
@GuardedBy("mLock")
private int[] revokeUnusedSharedUserPermissionsLocked(
- SharedUserSetting suSetting, int[] allUserIds) {
+ List<AndroidPackage> pkgList, PermissionsState permissionsState, int[] allUserIds) {
// Collect all used permissions in the UID
final ArraySet<String> usedPermissions = new ArraySet<>();
- final List<AndroidPackage> pkgList = suSetting.getPackages();
if (pkgList == null || pkgList.size() == 0) {
return EmptyArray.INT;
}
@@ -3993,7 +4095,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- PermissionsState permissionsState = suSetting.getPermissionsState();
// Prune install permissions
List<PermissionState> installPermStates = permissionsState.getInstallPermissionStates();
final int installPermCount = installPermStates.size();
@@ -4279,12 +4380,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
} else {
mPackageManagerInt.forEachPackage(p -> {
- PackageSetting ps = mPackageManagerInt.getPackageSetting(
- p.getPackageName());
- if (ps == null) {
+ final PermissionsState permissionsState = getPermissionsState(p);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + p.getPackageName());
return;
}
- PermissionsState permissionsState = ps.getPermissionsState();
if (permissionsState.getInstallPermissionState(bp.getName()) != null) {
permissionsState.revokeInstallPermission(bp);
permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
@@ -4695,6 +4795,67 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return mBackgroundPermissions;
}
+ @Nullable
+ private PermissionsState getPermissionsState(@NonNull PackageSetting ps) {
+ return getPermissionsState(ps.getAppId());
+ }
+
+ @Nullable
+ private PermissionsState getPermissionsState(@NonNull AndroidPackage pkg) {
+ return getPermissionsState(pkg.getUid());
+ }
+
+ @Nullable
+ private PermissionsState getPermissionsState(int appId) {
+ synchronized (mLock) {
+ return mAppIdStates.get(appId);
+ }
+ }
+
+ @Nullable
+ private PermissionsState getOrCreatePermissionsState(@NonNull PackageSetting ps) {
+ return getOrCreatePermissionsState(ps.getAppId());
+ }
+
+ @Nullable
+ private PermissionsState getOrCreatePermissionsState(int appId) {
+ synchronized (mLock) {
+ PermissionsState state = mAppIdStates.get(appId);
+ if (state == null) {
+ state = new PermissionsState();
+ mAppIdStates.put(appId, state);
+ }
+ return state;
+ }
+ }
+
+ private void removePermissionsState(int appId) {
+ synchronized (mLock) {
+ mAppIdStates.remove(appId);
+ }
+ }
+
+ private void readPermissionsStateFromPackageSettings() {
+ mPackageManagerInt.forEachPackageSetting(ps -> {
+ synchronized (mLock) {
+ mAppIdStates.put(ps.getAppId(), new PermissionsState(ps.getPermissionsState()));
+ }
+ });
+ }
+
+ private void writePermissionsStateToPackageSettings() {
+ mPackageManagerInt.forEachPackageSetting(ps -> {
+ synchronized (mLock) {
+ final PermissionsState permissionsState = mAppIdStates.get(ps.getAppId());
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + ps.name);
+ return;
+ }
+ ps.getPermissionsState().copyFrom(permissionsState);
+ }
+ });
+ }
+
private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal {
@Override
public void systemReady() {
@@ -4726,6 +4887,29 @@ public class PermissionManagerService extends IPermissionManager.Stub {
public void removeAllPermissions(AndroidPackage pkg, boolean chatty) {
PermissionManagerService.this.removeAllPermissions(pkg, chatty);
}
+ @Override
+ public void readPermissionsStateFromPackageSettingsTEMP() {
+ PermissionManagerService.this.readPermissionsStateFromPackageSettings();
+ }
+ @Override
+ public void writePermissionsStateToPackageSettingsTEMP() {
+ PermissionManagerService.this.writePermissionsStateToPackageSettings();
+ }
+ @Override
+ public void onUserRemoved(@UserIdInt int userId) {
+ PermissionManagerService.this.onUserRemoved(userId);
+ }
+ @Override
+ public void removePermissionsStateTEMP(int appId) {
+ PermissionManagerService.this.removePermissionsState(appId);
+ }
+ @Override
+ @UserIdInt
+ public int revokeSharedUserPermissionsForDeletedPackageTEMP(
+ @NonNull PackageSetting deletedPs, @UserIdInt int userId) {
+ return PermissionManagerService.this.revokeSharedUserPermissionsForDeletedPackage(
+ deletedPs, userId);
+ }
@NonNull
@Override
public Set<String> getGrantedPermissions(@NonNull String packageName,
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index cfa371ddbad3..f319bf495e8b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -24,6 +24,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.permission.PermissionManagerInternal;
+import com.android.server.pm.PackageSetting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.util.ArrayList;
@@ -265,6 +266,52 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
/**
+ * Read {@code PermissionsState} from package settings.
+ *
+ * TODO(zhanghai): This is a temporary method because we should not expose
+ * {@code PackageSetting} which is a implementation detail that permission should not know.
+ * Instead, it should retrieve the legacy state via a defined API.
+ */
+ public abstract void readPermissionsStateFromPackageSettingsTEMP();
+
+ /**
+ * Write {@code PermissionsState} from to settings.
+ *
+ * TODO(zhanghai): This is a temporary method and should be removed once we migrated persistence
+ * for permission.
+ */
+ public abstract void writePermissionsStateToPackageSettingsTEMP();
+
+ /**
+ * Notify that a user has been removed and its permission state should be removed as well.
+ */
+ public abstract void onUserRemoved(@UserIdInt int userId);
+
+ /**
+ * Remove the {@code PermissionsState} associated with an app ID, called the same time as the
+ * removal of a {@code PackageSetitng}.
+ *
+ * TODO(zhanghai): This is a temporary method before we figure out a way to get notified of app
+ * ID removal via API.
+ */
+ public abstract void removePermissionsStateTEMP(int appId);
+
+ /**
+ * Update the shared user setting when a package with a shared user id is removed. The gids
+ * associated with each permission of the deleted package are removed from the shared user'
+ * gid list only if its not in use by other permissions of packages in the shared user setting.
+ *
+ * TODO(zhanghai): We should not need this when permission no longer sees an incomplete package
+ * state where the updated system package is uninstalled but the disabled system package is yet
+ * to be installed. Then we should handle this in restorePermissionState().
+ *
+ * @return the affected user id, may be a real user ID, USER_ALL, or USER_NULL when none.
+ */
+ @UserIdInt
+ public abstract int revokeSharedUserPermissionsForDeletedPackageTEMP(
+ @NonNull PackageSetting deletedPs, @UserIdInt int userId);
+
+ /**
* Get all the permissions granted to a package.
*/
@NonNull
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 548cd70de4d1..137c587b1d79 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2219,11 +2219,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
- public int getMaxWallpaperLayer() {
- return getWindowLayerFromTypeLw(TYPE_NOTIFICATION_SHADE);
- }
-
- @Override
public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
return attrs.type == TYPE_NOTIFICATION_SHADE;
}
@@ -5324,15 +5319,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
- public boolean isTopLevelWindow(int windowType) {
- if (windowType >= WindowManager.LayoutParams.FIRST_SUB_WINDOW
- && windowType <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
- return (windowType == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG);
- }
- return true;
- }
-
- @Override
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(ROTATION_MODE, mDefaultDisplayRotation.getUserRotationMode());
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 651eafd77fe7..b96d65cb7433 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -67,7 +67,6 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.WindowConfiguration;
import android.content.Context;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -90,7 +89,6 @@ import android.view.animation.Animation;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
import com.android.server.wm.DisplayRotation;
-import com.android.server.wm.WindowFrames;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -181,92 +179,11 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
*/
public interface WindowState {
/**
- * Return the uid of the app that owns this window.
- */
- int getOwningUid();
-
- /**
* Return the package name of the app that owns this window.
*/
String getOwningPackage();
/**
- * Perform standard frame computation. The result can be obtained with
- * getFrame() if so desired. Must be called with the window manager
- * lock held.
- *
- */
- public void computeFrameLw();
-
- /**
- * Retrieve the current frame of the window that has been assigned by
- * the window manager. Must be called with the window manager lock held.
- *
- * @return Rect The rectangle holding the window frame.
- */
- public Rect getFrameLw();
-
- /**
- * Retrieve the frame of the display that this window was last
- * laid out in. Must be called with the
- * window manager lock held.
- *
- * @return Rect The rectangle holding the display frame.
- */
- public Rect getDisplayFrameLw();
-
- /**
- * Retrieve the frame of the content area that this window was last
- * laid out in. This is the area in which the content of the window
- * should be placed. It will be smaller than the display frame to
- * account for screen decorations such as a status bar or soft
- * keyboard. Must be called with the
- * window manager lock held.
- *
- * @return Rect The rectangle holding the content frame.
- */
- public Rect getContentFrameLw();
-
- /**
- * Retrieve the frame of the visible area that this window was last
- * laid out in. This is the area of the screen in which the window
- * will actually be fully visible. It will be smaller than the
- * content frame to account for transient UI elements blocking it
- * such as an input method's candidates UI. Must be called with the
- * window manager lock held.
- *
- * @return Rect The rectangle holding the visible frame.
- */
- public Rect getVisibleFrameLw();
-
- /**
- * Returns true if this window is waiting to receive its given
- * internal insets from the client app, and so should not impact the
- * layout of other windows.
- */
- public boolean getGivenInsetsPendingLw();
-
- /**
- * Retrieve the insets given by this window's client for the content
- * area of windows behind it. Must be called with the
- * window manager lock held.
- *
- * @return Rect The left, top, right, and bottom insets, relative
- * to the window's frame, of the actual contents.
- */
- public Rect getGivenContentInsetsLw();
-
- /**
- * Retrieve the insets given by this window's client for the visible
- * area of windows behind it. Must be called with the
- * window manager lock held.
- *
- * @return Rect The left, top, right, and bottom insets, relative
- * to the window's frame, of the actual visible area.
- */
- public Rect getGivenVisibleInsetsLw();
-
- /**
* Retrieve the current LayoutParams of the window.
*
* @return WindowManager.LayoutParams The window's internal LayoutParams
@@ -275,17 +192,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public WindowManager.LayoutParams getAttrs();
/**
- * Retrieve the current system UI visibility flags associated with
- * this window.
- */
- public int getSystemUiVisibility();
-
- /**
- * Get the layer at which this window's surface will be Z-ordered.
- */
- public int getSurfaceLayer();
-
- /**
* Retrieve the type of the top-level window.
*
* @return the base type of the parent window if attached or its own type otherwise
@@ -301,22 +207,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public IApplicationToken getAppToken();
/**
- * Return true if this window is participating in voice interaction.
- */
- public boolean isVoiceInteraction();
-
- /**
- * Return true if, at any point, the application token associated with
- * this window has actually displayed any windows. This is most useful
- * with the "starting up" window to determine if any windows were
- * displayed when it is closed.
- *
- * @return Returns true if one or more windows have been displayed,
- * else false.
- */
- public boolean hasAppShownWindows();
-
- /**
* Is this window visible? It is not visible if there is no
* surface, or we are in the process of running an exit animation
* that will remove the surface.
@@ -324,42 +214,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
boolean isVisibleLw();
/**
- * Is this window currently visible to the user on-screen? It is
- * displayed either if it is visible or it is currently running an
- * animation before no longer being visible. Must be called with the
- * window manager lock held.
- */
- boolean isDisplayedLw();
-
- /**
* Return true if this window (or a window it is attached to, but not
* considering its app token) is currently animating.
*/
boolean isAnimatingLw();
/**
- * Is this window considered to be gone for purposes of layout?
- */
- boolean isGoneForLayoutLw();
-
- /**
- * Returns true if the window has a surface that it has drawn a
- * complete UI in to. Note that this is different from {@link #hasDrawnLw()}
- * in that it also returns true if the window is READY_TO_SHOW, but was not yet
- * promoted to HAS_DRAWN.
- */
- boolean isDrawnLw();
-
- /**
- * Returns true if this window has been shown on screen at some time in
- * the past. Must be called with the window manager lock held.
- *
- * @deprecated Use {@link #isDrawnLw} or any of the other drawn/visibility methods.
- */
- @Deprecated
- public boolean hasDrawnLw();
-
- /**
* Can be called by the policy to force a window to be hidden,
* regardless of whether the client or window manager would like
* it shown. Must be called with the window manager lock held.
@@ -377,51 +237,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public boolean showLw(boolean doAnimation);
/**
- * Check whether the process hosting this window is currently alive.
- */
- public boolean isAlive();
-
- /**
- * Check if window is on {@link Display#DEFAULT_DISPLAY}.
- * @return true if window is on default display.
- */
- public boolean isDefaultDisplay();
-
- /**
* Check whether the window is currently dimming.
*/
public boolean isDimming();
- /**
- * Returns true if the window is letterboxed for the display cutout.
- */
- default boolean isLetterboxedForDisplayCutoutLw() {
- return false;
- }
-
- /** @return the current windowing mode of this window. */
- int getWindowingMode();
-
- /**
- * Returns the {@link WindowConfiguration.ActivityType} associated with the configuration
- * of this window.
- */
- default int getActivityType() {
- return WindowConfiguration.WINDOWING_MODE_UNDEFINED;
- }
-
- /**
- * Returns true if the window is current in multi-windowing mode. i.e. it shares the
- * screen with other application windows.
- */
- boolean inMultiWindowMode();
-
- public int getRotationAnimationHint();
-
public boolean isInputMethodWindow();
- public boolean isInputMethodTarget();
-
public int getDisplayId();
/**
@@ -432,42 +253,8 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
return false;
}
- /**
- * Returns true if the window owner has the permission to acquire a sleep token when it's
- * visible. That is, they have the permission {@link Manifest.permission#DEVICE_POWER}.
- */
- boolean canAcquireSleepToken();
-
- /** @return true if this window desires key events. */
- boolean canReceiveKeys();
-
/** @return true if the window can show over keyguard. */
boolean canShowWhenLocked();
-
- /**
- * Writes {@link com.android.server.wm.IdentifierProto} to stream.
- */
- void writeIdentifierToProto(ProtoOutputStream proto, long fieldId);
-
- /**
- * @return The {@link WindowFrames} associated with this {@link WindowState}
- */
- WindowFrames getWindowFrames();
- }
-
- /**
- * Representation of a input consumer that the policy has added to the
- * window manager to consume input events going to windows below it.
- */
- public interface InputConsumer {
- /**
- * Remove the input consumer from the window manager.
- */
- void dismiss();
- /**
- * Dispose the input consumer and input receiver from UI thread.
- */
- void dispose();
}
/**
@@ -538,11 +325,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
void unregisterPointerEventListener(PointerEventListener listener, int displayId);
/**
- * @return The currently active input method window.
- */
- WindowState getInputMethodWindowLw();
-
- /**
* Notifies window manager that {@link #isKeyguardTrustedLw} has changed.
*/
void notifyKeyguardTrustedChanged();
@@ -615,17 +397,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
}
/**
- * Provides the rotation of a device.
- *
- * @see com.android.server.policy.WindowOrientationListener
- */
- public interface RotationSource {
- int getProposedRotation();
-
- void setCurrentRotation(int rotation);
- }
-
- /**
* Interface to get public information of a display content.
*/
public interface DisplayContentInfo {
@@ -889,12 +660,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
}
/**
- * Get the highest layer (actually one more than) that the wallpaper is
- * allowed to be in.
- */
- public int getMaxWallpaperLayer();
-
- /**
* Return whether the given window can become the Keyguard window. Typically returns true for
* the StatusBar.
*/
@@ -1384,17 +1149,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
void dumpDebug(ProtoOutputStream proto, long fieldId);
/**
- * Returns whether a given window type is considered a top level one.
- * A top level window does not have a container, i.e. attached window,
- * or if it has a container it is laid out as a top-level window, not
- * as a child of its container.
- *
- * @param windowType The window type.
- * @return True if the window is a top level one.
- */
- public boolean isTopLevelWindow(int windowType);
-
- /**
* Notifies the keyguard to start fading out.
*
* @param startTime the start time of the animation in uptime milliseconds
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 8f0fd607f928..d4375eb2935b 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -94,6 +94,7 @@ public class Notifier {
private static final int MSG_USER_ACTIVITY = 1;
private static final int MSG_BROADCAST = 2;
private static final int MSG_WIRELESS_CHARGING_STARTED = 3;
+ private static final int MSG_BROADCAST_ENHANCED_PREDICTION = 4;
private static final int MSG_PROFILE_TIMED_OUT = 5;
private static final int MSG_WIRED_CHARGING_STARTED = 6;
@@ -701,6 +702,16 @@ public class Notifier {
mPolicy.userActivity();
}
+ void postEnhancedDischargePredictionBroadcast(long delayMs) {
+ mHandler.sendEmptyMessageDelayed(MSG_BROADCAST_ENHANCED_PREDICTION, delayMs);
+ }
+
+ private void sendEnhancedDischargePredictionBroadcast() {
+ Intent intent = new Intent(PowerManager.ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ }
+
private void sendNextBroadcast() {
final int powerState;
synchronized (mLock) {
@@ -872,6 +883,10 @@ public class Notifier {
case MSG_WIRELESS_CHARGING_STARTED:
showWirelessChargingStarted(msg.arg1, msg.arg2);
break;
+ case MSG_BROADCAST_ENHANCED_PREDICTION:
+ removeMessages(MSG_BROADCAST_ENHANCED_PREDICTION);
+ sendEnhancedDischargePredictionBroadcast();
+ break;
case MSG_PROFILE_TIMED_OUT:
lockProfile(msg.arg1);
break;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 882ed1b7960b..9ff164ac4a7b 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -56,6 +56,7 @@ import android.os.IBinder;
import android.os.IPowerManager;
import android.os.Looper;
import android.os.Message;
+import android.os.ParcelDuration;
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.PowerManager.WakeData;
@@ -89,11 +90,13 @@ import android.view.Display;
import android.view.KeyEvent;
import com.android.internal.BrightnessSynchronizer;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
import com.android.server.EventLogTags;
import com.android.server.LockGuard;
import com.android.server.RescueParty;
@@ -238,6 +241,18 @@ public final class PowerManagerService extends SystemService
private static final int HALT_MODE_REBOOT = 1;
private static final int HALT_MODE_REBOOT_SAFE_MODE = 2;
+ /**
+ * How stale we'll allow the enhanced discharge prediction values to get before considering them
+ * invalid.
+ */
+ private static final long ENHANCED_DISCHARGE_PREDICTION_TIMEOUT_MS = 30 * 60 * 1000L;
+
+ /**
+ * The minimum amount of time between sending consequent
+ * {@link PowerManager#ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED} broadcasts.
+ */
+ private static final long ENHANCED_DISCHARGE_PREDICTION_BROADCAST_MIN_DELAY_MS = 60 * 1000L;
+
private final Context mContext;
private final ServiceThread mHandlerThread;
private final Handler mHandler;
@@ -380,6 +395,34 @@ public final class PowerManagerService extends SystemService
// The current battery level percentage.
private int mBatteryLevel;
+ /**
+ * The lock that should be held when interacting with {@link #mEnhancedDischargeTimeElapsed},
+ * {@link #mLastEnhancedDischargeTimeUpdatedElapsed}, and
+ * {@link #mEnhancedDischargePredictionIsPersonalized}.
+ */
+ private final Object mEnhancedDischargeTimeLock = new Object();
+
+ /**
+ * The time (in the elapsed realtime timebase) at which the battery level will reach 0%. This
+ * is provided as an enhanced estimate and only valid if
+ * {@link #mLastEnhancedDischargeTimeUpdatedElapsed} is greater than 0.
+ */
+ @GuardedBy("mEnhancedDischargeTimeLock")
+ private long mEnhancedDischargeTimeElapsed;
+
+ /**
+ * Timestamp (in the elapsed realtime timebase) of last update to enhanced battery estimate
+ * data.
+ */
+ @GuardedBy("mEnhancedDischargeTimeLock")
+ private long mLastEnhancedDischargeTimeUpdatedElapsed;
+
+ /**
+ * Whether or not the current enhanced discharge prediction is personalized to the user.
+ */
+ @GuardedBy("mEnhancedDischargeTimeLock")
+ private boolean mEnhancedDischargePredictionIsPersonalized;
+
// The battery level percentage at the time the dream started.
// This is used to terminate a dream and go to sleep if the battery is
// draining faster than it is charging and the user activity timeout has expired.
@@ -3737,6 +3780,13 @@ public final class PowerManagerService extends SystemService
pw.println(" mProximityPositive=" + mProximityPositive);
pw.println(" mBootCompleted=" + mBootCompleted);
pw.println(" mSystemReady=" + mSystemReady);
+ synchronized (mEnhancedDischargeTimeLock) {
+ pw.println(" mEnhancedDischargeTimeElapsed=" + mEnhancedDischargeTimeElapsed);
+ pw.println(" mLastEnhancedDischargeTimeUpdatedElapsed="
+ + mLastEnhancedDischargeTimeUpdatedElapsed);
+ pw.println(" mEnhancedDischargePredictionIsPersonalized="
+ + mEnhancedDischargePredictionIsPersonalized);
+ }
pw.println(" mHalAutoSuspendModeEnabled=" + mHalAutoSuspendModeEnabled);
pw.println(" mHalInteractiveModeEnabled=" + mHalInteractiveModeEnabled);
pw.println(" mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
@@ -3952,6 +4002,16 @@ public final class PowerManagerService extends SystemService
proto.write(PowerManagerServiceDumpProto.IS_PROXIMITY_POSITIVE, mProximityPositive);
proto.write(PowerManagerServiceDumpProto.IS_BOOT_COMPLETED, mBootCompleted);
proto.write(PowerManagerServiceDumpProto.IS_SYSTEM_READY, mSystemReady);
+ synchronized (mEnhancedDischargeTimeLock) {
+ proto.write(PowerManagerServiceDumpProto.ENHANCED_DISCHARGE_TIME_ELAPSED,
+ mEnhancedDischargeTimeElapsed);
+ proto.write(
+ PowerManagerServiceDumpProto.LAST_ENHANCED_DISCHARGE_TIME_UPDATED_ELAPSED,
+ mLastEnhancedDischargeTimeUpdatedElapsed);
+ proto.write(
+ PowerManagerServiceDumpProto.IS_ENHANCED_DISCHARGE_PREDICTION_PERSONALIZED,
+ mEnhancedDischargePredictionIsPersonalized);
+ }
proto.write(
PowerManagerServiceDumpProto.IS_HAL_AUTO_SUSPEND_MODE_ENABLED,
mHalAutoSuspendModeEnabled);
@@ -3959,7 +4019,8 @@ public final class PowerManagerService extends SystemService
PowerManagerServiceDumpProto.IS_HAL_AUTO_INTERACTIVE_MODE_ENABLED,
mHalInteractiveModeEnabled);
- final long activeWakeLocksToken = proto.start(PowerManagerServiceDumpProto.ACTIVE_WAKE_LOCKS);
+ final long activeWakeLocksToken = proto.start(
+ PowerManagerServiceDumpProto.ACTIVE_WAKE_LOCKS);
proto.write(
PowerManagerServiceDumpProto.ActiveWakeLocksProto.IS_CPU,
(mWakeLockSummary & WAKE_LOCK_CPU) != 0);
@@ -4262,6 +4323,7 @@ public final class PowerManagerService extends SystemService
if (wcd != null) {
wcd.dumpDebug(proto, PowerManagerServiceDumpProto.WIRELESS_CHARGER_DETECTOR);
}
+
proto.flush();
}
@@ -5022,6 +5084,96 @@ public final class PowerManagerService extends SystemService
}
@Override // Binder call
+ public void setBatteryDischargePrediction(@NonNull ParcelDuration timeRemaining,
+ boolean isPersonalized) {
+ // Get current time before acquiring the lock so that the calculated end time is as
+ // accurate as possible.
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+ final long timeRemainingMs = timeRemaining.getDuration().toMillis();
+ // A non-positive number means the battery should be dead right now...
+ Preconditions.checkArgumentPositive(timeRemainingMs,
+ "Given time remaining is not positive: " + timeRemainingMs);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ if (mIsPowered) {
+ throw new IllegalStateException(
+ "Discharge prediction can't be set while the device is charging");
+ }
+ }
+
+ final long broadcastDelayMs;
+ synchronized (mEnhancedDischargeTimeLock) {
+ if (mLastEnhancedDischargeTimeUpdatedElapsed > nowElapsed) {
+ // Another later call made it into the block first. Keep the latest info.
+ return;
+ }
+ broadcastDelayMs = Math.max(0,
+ ENHANCED_DISCHARGE_PREDICTION_BROADCAST_MIN_DELAY_MS
+ - (nowElapsed - mLastEnhancedDischargeTimeUpdatedElapsed));
+
+ // No need to persist the discharge prediction values since they'll most likely
+ // be wrong immediately after a reboot anyway.
+ mEnhancedDischargeTimeElapsed = nowElapsed + timeRemainingMs;
+ mEnhancedDischargePredictionIsPersonalized = isPersonalized;
+ mLastEnhancedDischargeTimeUpdatedElapsed = nowElapsed;
+ }
+ mNotifier.postEnhancedDischargePredictionBroadcast(broadcastDelayMs);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private boolean isEnhancedDischargePredictionValidLocked(long nowElapsed) {
+ return mLastEnhancedDischargeTimeUpdatedElapsed > 0
+ && nowElapsed < mEnhancedDischargeTimeElapsed
+ && nowElapsed - mLastEnhancedDischargeTimeUpdatedElapsed
+ < ENHANCED_DISCHARGE_PREDICTION_TIMEOUT_MS;
+ }
+
+ @Override // Binder call
+ public ParcelDuration getBatteryDischargePrediction() {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ if (mIsPowered) {
+ return null;
+ }
+ }
+ synchronized (mEnhancedDischargeTimeLock) {
+ // Get current time after acquiring the lock so that the calculated duration
+ // is as accurate as possible.
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ if (isEnhancedDischargePredictionValidLocked(nowElapsed)) {
+ return new ParcelDuration(mEnhancedDischargeTimeElapsed - nowElapsed);
+ }
+ }
+ return new ParcelDuration(mBatteryStats.computeBatteryTimeRemaining());
+ } catch (RemoteException e) {
+ // Shouldn't happen in-process.
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return null;
+ }
+
+ @Override // Binder call
+ public boolean isBatteryDischargePredictionPersonalized() {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mEnhancedDischargeTimeLock) {
+ return isEnhancedDischargePredictionValidLocked(SystemClock.elapsedRealtime())
+ && mEnhancedDischargePredictionIsPersonalized;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
public boolean isDeviceIdleMode() {
final long ident = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 6dc1d6921dbb..0abeac890df1 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -336,11 +336,12 @@ public final class StorageSessionController {
}
/**
- * Returns {@code true} if {@code vol} is an emulated or public volume,
+ * Returns {@code true} if {@code vol} is an emulated or visible public volume,
* {@code false} otherwise
**/
public static boolean isEmulatedOrPublic(VolumeInfo vol) {
- return vol.type == VolumeInfo.TYPE_EMULATED || vol.type == VolumeInfo.TYPE_PUBLIC;
+ return vol.type == VolumeInfo.TYPE_EMULATED
+ || (vol.type == VolumeInfo.TYPE_PUBLIC && vol.isVisible());
}
/** Exception thrown when communication with the {@link ExternalStorageService} fails. */
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index a106dc682208..0b0bb7059f3b 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -258,7 +258,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
- final int packageUid = pm.getPackageUidInternal(packageName,
+ final int packageUid = pm.getPackageUid(packageName,
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, callingUserId);
if (packageUid != callingUid) {
throw new SecurityException(
@@ -336,7 +336,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
if (toPackage != null) {
mAmInternal.enforceCallingPermission(FORCE_PERSISTABLE_URI_PERMISSIONS,
"takePersistableUriPermission");
- uid = mPmInternal.getPackageUidInternal(toPackage, 0, userId);
+ uid = mPmInternal.getPackageUid(toPackage, 0 /* flags */, userId);
} else {
enforceNotIsolatedCaller("takePersistableUriPermission");
uid = Binder.getCallingUid();
@@ -401,7 +401,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
if (toPackage != null) {
mAmInternal.enforceCallingPermission(FORCE_PERSISTABLE_URI_PERMISSIONS,
"releasePersistableUriPermission");
- uid = mPmInternal.getPackageUidInternal(toPackage, 0, userId);
+ uid = mPmInternal.getPackageUid(toPackage, 0 /* flags */ , userId);
} else {
enforceNotIsolatedCaller("releasePersistableUriPermission");
uid = Binder.getCallingUid();
@@ -600,7 +600,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
if (needed != null) {
targetUid = needed.targetUid;
} else {
- targetUid = mPmInternal.getPackageUidInternal(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
+ targetUid = mPmInternal.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
targetUserId);
if (targetUid < 0) {
if (DEBUG) Slog.v(TAG, "Can't grant URI permission no uid for: " + targetPkg
@@ -690,7 +690,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
final ProviderInfo pi = getProviderInfo(uri.getAuthority(), sourceUserId,
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
if (pi != null && sourcePkg.equals(pi.packageName)) {
- int targetUid = mPmInternal.getPackageUidInternal(
+ int targetUid = mPmInternal.getPackageUid(
targetPkg, MATCH_UNINSTALLED_PACKAGES, targetUserId);
if (targetUid != -1) {
final GrantUri grantUri = new GrantUri(sourceUserId, uri,
@@ -787,7 +787,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
if (targetPkg == null) {
throw new NullPointerException("targetPkg");
}
- int targetUid = mPmInternal.getPackageUidInternal(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
+ int targetUid = mPmInternal.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
targetUserId);
targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg, grantUri, modeFlags,
@@ -1108,7 +1108,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
int targetUid = lastTargetUid;
if (targetUid < 0 && targetPkg != null) {
- targetUid = mPmInternal.getPackageUidInternal(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
+ targetUid = mPmInternal.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
UserHandle.getUserId(callingUid));
if (targetUid < 0) {
if (DEBUG) Slog.v(TAG, "Can't grant URI permission no uid for: " + targetPkg);
@@ -1462,7 +1462,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
boolean printed = false;
int dumpUid = -2;
if (dumpPackage != null) {
- dumpUid = mPmInternal.getPackageUidInternal(dumpPackage, MATCH_ANY_USER, 0);
+ dumpUid = mPmInternal.getPackageUid(dumpPackage,
+ MATCH_ANY_USER, 0 /* userId */);
}
for (int i = 0; i < mGrantedUriPermissions.size(); i++) {
int uid = mGrantedUriPermissions.keyAt(i);
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 9bbeb728ae33..90a153be8800 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -209,8 +209,8 @@ public class WebViewUpdateService extends SystemService {
private void grantVisibilityToCaller(String webViewPackageName, int callingUid) {
final PackageManagerInternal pmInternal = LocalServices.getService(
PackageManagerInternal.class);
- final int webviewUid = pmInternal.getPackageUidInternal(
- webViewPackageName, 0, UserHandle.getUserId(callingUid));
+ final int webviewUid = pmInternal.getPackageUid(
+ webViewPackageName, 0 /* flags */, UserHandle.getUserId(callingUid));
pmInternal.grantImplicitAccess(UserHandle.getUserId(callingUid), null,
UserHandle.getAppId(callingUid), webviewUid,
true /*direct*/);
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 1536473ff0a1..4c2d0d08cd4e 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -700,8 +700,8 @@ final class AccessibilityController {
touchableRegion.getBounds(touchableFrame);
RectF windowFrame = mTempRectF;
windowFrame.set(touchableFrame);
- windowFrame.offset(-windowState.getFrameLw().left,
- -windowState.getFrameLw().top);
+ windowFrame.offset(-windowState.getFrame().left,
+ -windowState.getFrame().top);
matrix.mapRect(windowFrame);
Region windowBounds = mTempRegion2;
windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
@@ -730,7 +730,7 @@ final class AccessibilityController {
}
// Count letterbox into nonMagnifiedBounds
- if (windowState.isLetterboxedForDisplayCutoutLw()) {
+ if (windowState.isLetterboxedForDisplayCutout()) {
Region letterboxBounds = getLetterboxBounds(windowState);
nonMagnifiedBounds.op(letterboxBounds, Region.Op.UNION);
availableBounds.op(letterboxBounds, Region.Op.DIFFERENCE);
@@ -1429,11 +1429,11 @@ final class AccessibilityController {
// Account for all space in the task, whether the windows in it are
// touchable or not. The modal window blocks all touches from the task's
// area.
- unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace,
+ unaccountedSpace.op(windowState.getDisplayFrame(), unaccountedSpace,
Region.Op.REVERSE_DIFFERENCE);
} else {
// If a window has tap exclude region, we need to account it.
- final Region displayRegion = new Region(windowState.getDisplayFrameLw());
+ final Region displayRegion = new Region(windowState.getDisplayFrame());
final Region tapExcludeRegion = new Region();
windowState.getTapExcludeRegion(tapExcludeRegion);
displayRegion.op(tapExcludeRegion, displayRegion,
@@ -1470,7 +1470,7 @@ final class AccessibilityController {
// Move to origin as all transforms are captured by the matrix.
RectF windowFrame = mTempRectF;
windowFrame.set(rect);
- windowFrame.offset(-windowState.getFrameLw().left, -windowState.getFrameLw().top);
+ windowFrame.offset(-windowState.getFrame().left, -windowState.getFrame().top);
matrix.mapRect(windowFrame);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 64fa6ca590d2..964de1348c2c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1334,7 +1334,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (w == null || winHint != null && w != winHint) {
return;
}
- final boolean surfaceReady = w.isDrawnLw() // Regular case
+ final boolean surfaceReady = w.isDrawn() // Regular case
|| w.mWinAnimator.mSurfaceDestroyDeferred // The preserved surface is still ready.
|| w.isDragResizeChanged(); // Waiting for relayoutWindow to call preserveSurface.
final boolean needsLetterbox = surfaceReady && w.isLetterboxedAppWindow() && fillsParent();
@@ -1355,7 +1355,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
: inMultiWindowMode()
? task.getBounds()
: getRootTask().getParent().getBounds();
- mLetterbox.layout(spaceToFill, w.getFrameLw(), mTmpPoint);
+ mLetterbox.layout(spaceToFill, w.getFrame(), mTmpPoint);
} else if (mLetterbox != null) {
mLetterbox.hide();
}
@@ -2786,8 +2786,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
makeFinishingLocked();
- final boolean activityRemoved = destroyImmediately(true /* removeFromApp */,
- "finish-imm:" + reason);
+ final boolean activityRemoved = destroyImmediately("finish-imm:" + reason);
// If the display does not have running activity, the configuration may need to be
// updated for restoring original orientation of the display.
@@ -2835,7 +2834,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* @return {@code true} if activity was immediately removed from history, {@code false}
* otherwise.
*/
- boolean destroyImmediately(boolean removeFromApp, String reason) {
+ boolean destroyImmediately(String reason) {
if (DEBUG_SWITCH || DEBUG_CLEANUP) {
Slog.v(TAG_SWITCH, "Removing activity from " + reason + ": token=" + this
+ ", app=" + (hasProcess() ? app.mName : "(null)"));
@@ -2857,17 +2856,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
cleanUp(false /* cleanServices */, false /* setState */);
if (hasProcess()) {
- if (removeFromApp) {
- app.removeActivity(this, true /* keepAssociation */);
- if (!app.hasActivities()) {
- mAtmService.clearHeavyWeightProcessIfEquals(app);
- // Update any services we are bound to that might care about whether
- // their client may have activities.
- // No longer have activities, so update LRU list and oom adj.
- app.updateProcessInfo(true /* updateServiceConnectionActivities */,
- false /* activityChange */, true /* updateOomAdj */,
- false /* addPendingTopUid */);
- }
+ app.removeActivity(this, true /* keepAssociation */);
+ if (!app.hasActivities()) {
+ mAtmService.clearHeavyWeightProcessIfEquals(app);
}
boolean skipDestroy = false;
@@ -2934,7 +2925,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
+ " pausing=" + stack.mPausingActivity
+ " for reason " + reason);
}
- return destroyImmediately(true /* removeFromApp */, reason);
+ return destroyImmediately(reason);
}
return false;
}
@@ -4305,7 +4296,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} else {
// If we are being set visible, and the starting window is not yet displayed,
// then make sure it doesn't get displayed.
- if (startingWindow != null && !startingWindow.isDrawnLw()) {
+ if (startingWindow != null && !startingWindow.isDrawn()) {
startingWindow.clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
startingWindow.mLegacyPolicyVisibilityAfterAnim = false;
}
@@ -4487,16 +4478,40 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
detachChildren();
}
- if (state == RESUMED) {
- mAtmService.updateBatteryStats(this, true);
- mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_RESUMED);
- } else if (state == PAUSED) {
- mAtmService.updateBatteryStats(this, false);
- mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED);
- } else if (state == STOPPED) {
- mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED);
- } else if (state == DESTROYED) {
- mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_DESTROYED);
+ switch (state) {
+ case RESUMED:
+ mAtmService.updateBatteryStats(this, true);
+ mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_RESUMED);
+ // Fall through.
+ case STARTED:
+ // Update process info while making an activity from invisible to visible, to make
+ // sure the process state is updated to foreground.
+ if (app != null) {
+ app.updateProcessInfo(false /* updateServiceConnectionActivities */,
+ true /* activityChange */, true /* updateOomAdj */,
+ true /* addPendingTopUid */);
+ }
+ break;
+ case PAUSED:
+ mAtmService.updateBatteryStats(this, false);
+ mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED);
+ break;
+ case STOPPED:
+ mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED);
+ break;
+ case DESTROYED:
+ mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_DESTROYED);
+ // Fall through.
+ case DESTROYING:
+ if (app != null && !app.hasActivities()) {
+ // Update any services we are bound to that might care about whether
+ // their client may have activities.
+ // No longer have activities, so update LRU list and oom adj.
+ app.updateProcessInfo(true /* updateServiceConnectionActivities */,
+ false /* activityChange */, true /* updateOomAdj */,
+ false /* addPendingTopUid */);
+ }
+ break;
}
}
@@ -4664,7 +4679,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// case where this is the top activity in a pinned stack.
final boolean isTop = this == stack.getTopNonFinishingActivity();
final boolean isTopNotPinnedStack = stack.isAttached()
- && stack.getDisplayArea().isTopNotPinnedStack(stack);
+ && stack.getDisplayArea().isTopNotFinishNotPinnedStack(stack);
final boolean visibleIgnoringDisplayStatus = stack.checkKeyguardVisibility(this,
visibleIgnoringKeyguard, isTop && isTopNotPinnedStack);
@@ -4806,6 +4821,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
Slog.v(TAG_VISIBILITY, "Start visible activity, " + this);
}
setState(STARTED, "makeActiveIfNeeded");
+
try {
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
StartActivityItem.obtain());
@@ -5113,7 +5129,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (DEBUG_STATES) Slog.v(TAG_STATES, "Stop failed; moving to STOPPED: " + this);
setState(STOPPED, "stopIfPossible");
if (deferRelaunchUntilPaused) {
- destroyImmediately(true /* removeFromApp */, "stop-except");
+ destroyImmediately("stop-except");
}
}
}
@@ -5154,7 +5170,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
clearOptionsLocked();
} else {
if (deferRelaunchUntilPaused) {
- destroyImmediately(true /* removeFromApp */, "stop-config");
+ destroyImmediately("stop-config");
mRootWindowContainer.resumeFocusedStacksTopActivities();
} else {
mRootWindowContainer.updatePreviousProcess(this);
@@ -5580,9 +5596,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) {
final boolean isAnimationSet = isAnimating(TRANSITION | PARENTS,
ANIMATION_TYPE_APP_TRANSITION);
- Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
+ Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawn()
+ ", isAnimationSet=" + isAnimationSet);
- if (!w.isDrawnLw()) {
+ if (!w.isDrawn()) {
Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController
+ " pv=" + w.isVisibleByPolicy()
+ " mDrawState=" + winAnimator.drawStateToString()
@@ -5597,7 +5613,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (findMainWindow(false /* includeStartingApp */) != w) {
mNumInterestingWindows++;
}
- if (w.isDrawnLw()) {
+ if (w.isDrawn()) {
mNumDrawnWindows++;
if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) {
@@ -5610,7 +5626,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
isInterestingAndDrawn = true;
}
}
- } else if (w.isDrawnLw()) {
+ } else if (w.isDrawn()) {
// The starting window for this container is drawn.
mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(this);
startingDisplayed = true;
@@ -6139,7 +6155,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (win == null) {
return;
}
- final Rect frame = win.getRelativeFrameLw();
+ final Rect frame = win.getRelativeFrame();
final int thumbnailDrawableRes = task.mUserId == mWmService.mCurrentUserId
? R.drawable.ic_account_circle
: R.drawable.ic_corp_badge;
@@ -6165,7 +6181,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// destination of the thumbnail header animation. If this is a full screen
// window scenario, we use the whole display as the target.
WindowState win = findMainWindow();
- Rect appRect = win != null ? win.getContentFrameLw() :
+ final Rect appRect = win != null ? win.getContentFrame() :
new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
final Rect insets = win != null ? win.getContentInsets() : null;
final Configuration displayConfig = mDisplayContent.getConfiguration();
@@ -7104,7 +7120,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (!attachedToProcess()) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is destroying non-running " + this);
- destroyImmediately(true /* removeFromApp */, "config");
+ destroyImmediately("config");
} else if (mState == PAUSING) {
// A little annoying: we are waiting for this activity to finish pausing. Let's not
// do anything now, but just flag that it needs to be restarted when done pausing.
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 2c475e0b9bcb..34f7f79d7716 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -41,10 +41,8 @@ import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static android.os.Process.INVALID_UID;
-import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.TYPE_VIRTUAL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
@@ -1869,7 +1867,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
for (int i = 0; i < numFinishingActivities; i++) {
final ActivityRecord r = finishingActivities.get(i);
if (r.isInHistory()) {
- r.destroyImmediately(true /* removeFromApp */, "finish-" + reason);
+ r.destroyImmediately("finish-" + reason);
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index f6158383d28a..4c93b9ef64de 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1693,8 +1693,9 @@ class ActivityStarter {
// we need to resolve resultTo to a uid as grantImplicitAccess deals explicitly in UIDs
final PackageManagerInternal pmInternal =
mService.getPackageManagerInternalLocked();
- final int resultToUid = pmInternal.getPackageUidInternal(
- mStartActivity.resultTo.info.packageName, 0, mStartActivity.mUserId);
+ final int resultToUid = pmInternal.getPackageUid(
+ mStartActivity.resultTo.info.packageName, 0 /* flags */,
+ mStartActivity.mUserId);
pmInternal.grantImplicitAccess(mStartActivity.mUserId, mIntent,
UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,
resultToUid /*visible*/, true /*direct*/);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 403f225032e9..2adaa52dfb30 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3379,7 +3379,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (r == null || !r.isDestroyable()) {
return false;
}
- r.destroyImmediately(true /* removeFromApp */, "app-req");
+ r.destroyImmediately("app-req");
return r.isState(DESTROYING, DESTROYED);
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index c1447553ba31..8568d5fc1d64 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -222,12 +222,12 @@ public class BarController {
}
protected boolean skipAnimation() {
- return !mWin.isDrawnLw();
+ return !mWin.isDrawn();
}
private @StatusBarManager.WindowVisibleState int computeStateLw(
boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
- if (win.isDrawnLw()) {
+ if (win.isDrawn()) {
final boolean vis = win.isVisibleLw();
final boolean anim = win.isAnimatingLw();
if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) {
@@ -264,7 +264,7 @@ public class BarController {
}
boolean checkHiddenLw() {
- if (mWin != null && mWin.isDrawnLw()) {
+ if (mWin != null && mWin.isDrawn()) {
if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) {
updateStateLw(StatusBarManager.WINDOW_STATE_HIDDEN);
}
@@ -291,7 +291,7 @@ public class BarController {
} else if (mWin == null) {
if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist");
return false;
- } else if (mWin.isDisplayedLw()) {
+ } else if (mWin.isDisplayed()) {
if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar already visible");
return false;
} else {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0215ead7e5de..2f7cc69b01a7 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -694,7 +694,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Don't do layout of a window if it is not visible, or soon won't be visible, to avoid
// wasting time and funky changes while a window is animating away.
final boolean gone = (mTmpWindow != null && mWmService.mPolicy.canBeHiddenByKeyguardLw(w))
- || w.isGoneForLayoutLw();
+ || w.isGoneForLayout();
if (DEBUG_LAYOUT && !w.mLayoutAttached) {
Slog.v(TAG, "1ST PASS " + w + ": gone=" + gone + " mHaveFrame=" + w.mHaveFrame
@@ -742,7 +742,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (firstLayout) {
// The client may compute its actual requested size according to the first layout,
// so we still request the window to resize if the current frame is empty.
- if (!w.getFrameLw().isEmpty()) {
+ if (!w.getFrame().isEmpty()) {
w.updateLastFrames();
}
w.updateLastInsetValues();
@@ -753,9 +753,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
w.mActivityRecord.layoutLetterbox(w);
}
- if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrameLw()
+ if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame()
+ " mContainingFrame=" + w.getContainingFrame()
- + " mDisplayFrame=" + w.getDisplayFrameLw());
+ + " mDisplayFrame=" + w.getDisplayFrame());
}
};
@@ -780,9 +780,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
w.prelayout();
getDisplayPolicy().layoutWindowLw(w, w.getParentWindow(), mDisplayFrames);
w.mLayoutSeq = mLayoutSeq;
- if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrameLw()
+ if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame()
+ " mContainingFrame=" + w.getContainingFrame()
- + " mDisplayFrame=" + w.getDisplayFrameLw());
+ + " mDisplayFrame=" + w.getDisplayFrame());
}
}
};
@@ -807,7 +807,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured;
if (!mTmpApplySurfaceChangesTransactionState.obscured) {
- final boolean isDisplayed = w.isDisplayedLw();
+ final boolean isDisplayed = w.isDisplayed();
if (isDisplayed && w.isObscuringDisplay()) {
// This window completely covers everything behind it, so we want to leave all
@@ -2549,7 +2549,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return;
}
- if (w.isOnScreen() && w.isVisibleLw() && w.getFrameLw().contains(x, y)) {
+ if (w.isOnScreen() && w.isVisibleLw() && w.getFrame().contains(x, y)) {
targetWindowType[0] = w.mAttrs.type;
return;
}
@@ -2747,7 +2747,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
void adjustForImeIfNeeded() {
final WindowState imeWin = mInputMethodWindow;
final boolean imeVisible = imeWin != null && imeWin.isVisibleLw()
- && imeWin.isDisplayedLw();
+ && imeWin.isDisplayed();
final int imeHeight = mDisplayFrames.getInputMethodWindowVisibleHeight();
mPinnedStackControllerLocked.setAdjustedForIme(imeVisible, imeHeight);
}
@@ -3364,7 +3364,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Now, a special case -- if the last target's window is in the process of exiting, but
// not removed, keep on the last target to avoid IME flicker. The exception is if the
// current target is home since we want opening apps to become the IME target right away.
- if (curTarget != null && !curTarget.mRemoved && curTarget.isDisplayedLw()
+ if (curTarget != null && !curTarget.mRemoved && curTarget.isDisplayed()
&& curTarget.isClosing() && !curTarget.isActivityTypeHome()) {
if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Not changing target till current window is"
+ " closing and not removed");
@@ -3647,7 +3647,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final WindowState visibleNotDrawnWindow = getWindow(w -> {
final boolean isVisible = w.isVisible() && !w.mObscured;
- final boolean isDrawn = w.isDrawnLw();
+ final boolean isDrawn = w.isDrawn();
if (isVisible && !isDrawn) {
ProtoLog.d(WM_DEBUG_BOOT,
"DisplayContent: boot is waiting for window of type %d to be drawn",
@@ -4599,9 +4599,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
DisplayContent dc = this;
do {
final WindowState displayParent = dc.getParentWindow();
- location.x += displayParent.getFrameLw().left
+ location.x += displayParent.getFrame().left
+ (dc.getLocationInParentWindow().x * displayParent.mGlobalScale + 0.5f);
- location.y += displayParent.getFrameLw().top
+ location.y += displayParent.getFrame().top
+ (dc.getLocationInParentWindow().y * displayParent.mGlobalScale + 0.5f);
dc = displayParent.getDisplayContent();
} while (dc != null && dc.getParentWindow() != null);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 2e03cb80b189..1c147c259f07 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -195,13 +195,13 @@ import com.android.internal.widget.PointerLocationView;
import com.android.server.LocalServices;
import com.android.server.UiThread;
import com.android.server.policy.WindowManagerPolicy;
-import com.android.server.policy.WindowManagerPolicy.InputConsumer;
import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition;
import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
import com.android.server.policy.WindowOrientationListener;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wallpaper.WallpaperManagerInternal;
+import com.android.server.wm.InputMonitor.EventReceiverInputConsumer;
import com.android.server.wm.utils.InsetUtils;
import java.io.PrintWriter;
@@ -246,6 +246,9 @@ public class DisplayPolicy {
| View.STATUS_BAR_TRANSPARENT
| View.NAVIGATION_BAR_TRANSPARENT;
+ private static final int[] SHOW_TYPES_FOR_SWIPE = {ITYPE_NAVIGATION_BAR, ITYPE_STATUS_BAR};
+ private static final int[] SHOW_TYPES_FOR_PANIC = {ITYPE_NAVIGATION_BAR};
+
private final WindowManagerService mService;
private final Context mContext;
private final Context mUiContext;
@@ -413,7 +416,7 @@ public class DisplayPolicy {
private boolean mAllowLockscreenWhenOn;
@VisibleForTesting
- InputConsumer mInputConsumer = null;
+ EventReceiverInputConsumer mInputConsumer;
private PointerLocationView mPointerLocationView;
@@ -459,7 +462,7 @@ public class DisplayPolicy {
}
break;
case MSG_DISPOSE_INPUT_CONSUMER:
- disposeInputConsumer((InputConsumer) msg.obj);
+ disposeInputConsumer((EventReceiverInputConsumer) msg.obj);
break;
case MSG_ENABLE_POINTER_LOCATION:
enablePointerLocation();
@@ -1123,7 +1126,7 @@ public class DisplayPolicy {
// For IME we use regular frame.
(displayFrames, windowState, inOutFrame) ->
- inOutFrame.set(windowState.getFrameLw()));
+ inOutFrame.set(windowState.getFrame()));
mDisplayContent.setInsetProvider(ITYPE_BOTTOM_GESTURES, win,
(displayFrames, windowState, inOutFrame) -> {
@@ -1200,11 +1203,11 @@ public class DisplayPolicy {
// IME should not provide frame which is smaller than the nav bar frame. Otherwise,
// nav bar might be overlapped with the content of the client when IME is shown.
sTmpRect.set(inOutFrame);
- sTmpRect.intersectUnchecked(mNavigationBar.getFrameLw());
- inOutFrame.inset(windowState.getGivenContentInsetsLw());
+ sTmpRect.intersectUnchecked(mNavigationBar.getFrame());
+ inOutFrame.inset(windowState.mGivenContentInsets);
inOutFrame.union(sTmpRect);
} else {
- inOutFrame.inset(windowState.getGivenContentInsetsLw());
+ inOutFrame.inset(windowState.mGivenContentInsets);
}
};
}
@@ -2072,7 +2075,7 @@ public class DisplayPolicy {
// In case we forced the window to draw behind the navigation bar, restrict df to
// DF.Restricted to simulate old compat behavior.
- Rect parentDisplayFrame = attached.getDisplayFrameLw();
+ Rect parentDisplayFrame = attached.getDisplayFrame();
final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
&& (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
@@ -2093,14 +2096,14 @@ public class DisplayPolicy {
// setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
// Otherwise, use the overscan frame.
cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
- ? attached.getContentFrameLw() : parentDisplayFrame);
+ ? attached.getContentFrame() : parentDisplayFrame);
} else {
// If the window is resizing, then we want to base the content frame on our attached
// content frame to resize...however, things can be tricky if the attached window is
// NOT in resize mode, in which case its content frame will be larger.
// Ungh. So to deal with that, make sure the content frame we end up using is not
// covering the IM dock.
- cf.set(attached.getContentFrameLw());
+ cf.set(attached.getContentFrame());
if (attached.isVoiceInteraction()) {
cf.intersectUnchecked(displayFrames.mVoiceContent);
} else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
@@ -2108,11 +2111,11 @@ public class DisplayPolicy {
}
}
df.set(insetDecors ? parentDisplayFrame : cf);
- vf.set(attached.getVisibleFrameLw());
+ vf.set(attached.getVisibleFrame());
}
// The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
// positioned relative to its parent or the entire screen.
- pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
+ pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df);
}
private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
@@ -2214,8 +2217,8 @@ public class DisplayPolicy {
vf.set(adjust != SOFT_INPUT_ADJUST_NOTHING
? displayFrames.mCurrent : displayFrames.mDock);
} else {
- pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
- vf.set(attached.getVisibleFrameLw());
+ pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df);
+ vf.set(attached.getVisibleFrame());
}
cf.set(adjust != SOFT_INPUT_ADJUST_RESIZE
? displayFrames.mDock : displayFrames.mContent);
@@ -2620,12 +2623,10 @@ public class DisplayPolicy {
win.computeFrame(displayFrames);
// Dock windows carve out the bottom of the screen, so normal windows
// can't appear underneath them.
- if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
- && !win.getGivenInsetsPendingLw()) {
+ if (type == TYPE_INPUT_METHOD && win.isVisibleLw() && !win.mGivenInsetsPending) {
offsetInputMethodWindowLw(win, displayFrames);
}
- if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
- && !win.getGivenInsetsPendingLw()) {
+ if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw() && !win.mGivenInsetsPending) {
offsetVoiceInputWindowLw(win, displayFrames);
}
}
@@ -2642,8 +2643,8 @@ public class DisplayPolicy {
final int navBarPosition = navigationBarPosition(displayFrames.mDisplayWidth,
displayFrames.mDisplayHeight, rotation);
- int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
- top += win.getGivenContentInsetsLw().top;
+ int top = Math.max(win.getDisplayFrame().top, win.getContentFrame().top);
+ top += win.mGivenContentInsets.top;
displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
if (navBarPosition == NAV_BAR_BOTTOM) {
// Always account for the nav bar frame height on the bottom since in all navigation
@@ -2655,8 +2656,8 @@ public class DisplayPolicy {
displayFrames.mUnrestricted.bottom - navFrameHeight);
}
displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
- top = win.getVisibleFrameLw().top;
- top += win.getGivenVisibleInsetsLw().top;
+ top = win.getVisibleFrame().top;
+ top += win.mGivenVisibleInsets.top;
displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
+ displayFrames.mDock.bottom + " mContentBottom="
@@ -2664,8 +2665,8 @@ public class DisplayPolicy {
}
private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
- int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
- top += win.getGivenContentInsetsLw().top;
+ int top = Math.max(win.getDisplayFrame().top, win.getContentFrame().top);
+ top += win.mGivenContentInsets.top;
displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
}
@@ -2726,8 +2727,7 @@ public class DisplayPolicy {
if (win.isDreamWindow()) {
// If the lockscreen was showing when the dream started then wait
// for the dream to draw before hiding the lockscreen.
- if (!mDreamingLockscreen
- || (win.isVisibleLw() && win.hasDrawnLw())) {
+ if (!mDreamingLockscreen || (win.isVisibleLw() && win.hasDrawn())) {
mShowingDream = true;
appWindow = true;
}
@@ -2913,7 +2913,7 @@ public class DisplayPolicy {
final InsetsSource request = mTopFullscreenOpaqueWindowState.getRequestedInsetsState()
.peekSource(ITYPE_STATUS_BAR);
if (WindowManagerDebugConfig.DEBUG) {
- Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
+ Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrame());
Slog.d(TAG, "attr: " + attrs + " request: " + request);
}
return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
@@ -3353,8 +3353,15 @@ public class DisplayPolicy {
return;
}
+ final InsetsState requestedState = controlTarget.getRequestedInsetsState();
+ final @InsetsType int restorePositionTypes =
+ (requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)
+ ? Type.navigationBars() : 0)
+ | (requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR)
+ ? Type.statusBars() : 0);
+
if (swipeTarget == mNavigationBar
- && !getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)) {
+ && (restorePositionTypes & Type.navigationBars()) != 0) {
// Don't show status bar when swiping on already visible navigation bar.
// But restore the position of navigation bar if it has been moved by the control
// target.
@@ -3362,14 +3369,13 @@ public class DisplayPolicy {
return;
}
- int insetsTypesToShow = Type.systemBars();
-
if (controlTarget.canShowTransient()) {
- insetsTypesToShow &= ~mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
- new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
- }
- if (insetsTypesToShow != 0) {
- controlTarget.showInsets(insetsTypesToShow, false);
+ // Show transient bars if they are hidden; restore position if they are visible.
+ mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE);
+ controlTarget.showInsets(restorePositionTypes, false);
+ } else {
+ // Restore visibilities and positions of system bars.
+ controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), false);
}
} else {
boolean sb = mStatusBarController.checkShowTransientBarLw();
@@ -3389,7 +3395,7 @@ public class DisplayPolicy {
mImmersiveModeConfirmation.confirmCurrentPrompt();
}
- private void disposeInputConsumer(InputConsumer inputConsumer) {
+ private void disposeInputConsumer(EventReceiverInputConsumer inputConsumer) {
if (inputConsumer != null) {
inputConsumer.dispose();
}
@@ -3770,8 +3776,7 @@ public class DisplayPolicy {
// we're no longer on the Keyguard and the screen is ready. We can now request the bars.
mPendingPanicGestureUptime = 0;
if (!isNavBarEmpty(vis)) {
- mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
- new int[] {ITYPE_NAVIGATION_BAR}));
+ mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_PANIC);
}
}
@@ -4163,6 +4168,6 @@ public class DisplayPolicy {
return false;
}
- return Rect.intersects(targetWindow.getFrameLw(), navBarWindow.getFrameLw());
+ return Rect.intersects(targetWindow.getFrame(), navBarWindow.getFrame());
}
}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 133b11116460..c9f463b8fbeb 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -283,8 +283,9 @@ class DragState {
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mDragWindowHandle.visible = true;
- mDragWindowHandle.canReceiveKeys = false;
- mDragWindowHandle.hasFocus = true;
+ // Allows the system to consume keys when dragging is active. This can also be used to
+ // modify the drag state on key press. Example, cancel drag on escape key.
+ mDragWindowHandle.focusable = true;
mDragWindowHandle.hasWallpaper = false;
mDragWindowHandle.paused = false;
mDragWindowHandle.ownerPid = Process.myPid();
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 86e2698302aa..f0f338534ed2 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -93,7 +93,7 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
|| (mImeTargetFromIme != null
&& isImeTargetFromDisplayContentAndImeSame()
&& mWin != null
- && mWin.isDrawnLw()
+ && mWin.isDrawn()
&& !mWin.mGivenInsetsPending)) {
mIsImeLayoutDrawn = true;
// show IME if InputMethodService requested it to be shown.
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 3b24584b0357..a79d3bb00907 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -80,8 +80,7 @@ class InputConsumerImpl implements IBinder.DeathRecipient {
mWindowHandle.layoutParamsFlags = 0;
mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mWindowHandle.visible = true;
- mWindowHandle.canReceiveKeys = false;
- mWindowHandle.hasFocus = false;
+ mWindowHandle.focusable = false;
mWindowHandle.hasWallpaper = false;
mWindowHandle.paused = false;
mWindowHandle.ownerPid = Process.myPid();
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 0fe9735c9e46..fb511e032c98 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -61,7 +61,6 @@ import android.view.InputWindowHandle;
import android.view.SurfaceControl;
import com.android.internal.protolog.common.ProtoLog;
-import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
import java.util.Set;
@@ -95,8 +94,11 @@ final class InputMonitor {
*/
private final ArrayMap<String, InputConsumerImpl> mInputConsumers = new ArrayMap();
- private static final class EventReceiverInputConsumer extends InputConsumerImpl
- implements WindowManagerPolicy.InputConsumer {
+ /**
+ * Representation of a input consumer that the policy has added to the window manager to consume
+ * input events going to windows below it.
+ */
+ static final class EventReceiverInputConsumer extends InputConsumerImpl {
private InputMonitor mInputMonitor;
private final InputEventReceiver mInputEventReceiver;
@@ -111,8 +113,8 @@ final class InputMonitor {
mClientChannel, looper);
}
- @Override
- public void dismiss() {
+ /** Removes the input consumer from the window manager. */
+ void dismiss() {
synchronized (mService.mGlobalLock) {
mInputMonitor.mInputConsumers.remove(mName);
hide(mInputMonitor.mInputTransaction);
@@ -120,8 +122,8 @@ final class InputMonitor {
}
}
- @Override
- public void dispose() {
+ /** Disposes the input consumer and input receiver from the associated thread. */
+ void dispose() {
synchronized (mService.mGlobalLock) {
disposeChannelsLw(mInputMonitor.mInputTransaction);
mInputEventReceiver.dispose();
@@ -225,8 +227,13 @@ final class InputMonitor {
}
}
- WindowManagerPolicy.InputConsumer createInputConsumer(Looper looper, String name,
+ EventReceiverInputConsumer createInputConsumer(Looper looper, String name,
InputEventReceiver.Factory inputEventReceiverFactory) {
+ if (!name.contentEquals(INPUT_CONSUMER_NAVIGATION)) {
+ throw new IllegalArgumentException("Illegal input consumer : " + name
+ + ", display: " + mDisplayId);
+ }
+
if (mInputConsumers.containsKey(name)) {
throw new IllegalStateException("Existing input consumer found with name: " + name
+ ", display: " + mDisplayId);
@@ -256,6 +263,11 @@ final class InputMonitor {
// stack, and we need FLAG_NOT_TOUCH_MODAL to ensure other events fall through
consumer.mWindowHandle.layoutParamsFlags |= FLAG_NOT_TOUCH_MODAL;
break;
+ case INPUT_CONSUMER_RECENTS_ANIMATION:
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal input consumer : " + name
+ + ", display: " + mDisplayId);
}
addInputConsumer(name, consumer);
}
@@ -271,8 +283,7 @@ final class InputMonitor {
inputWindowHandle.layoutParamsType = type;
inputWindowHandle.dispatchingTimeoutMillis = child.getInputDispatchingTimeoutMillis();
inputWindowHandle.visible = isVisible;
- inputWindowHandle.canReceiveKeys = child.canReceiveKeys();
- inputWindowHandle.hasFocus = hasFocus;
+ inputWindowHandle.focusable = hasFocus;
inputWindowHandle.hasWallpaper = hasWallpaper;
inputWindowHandle.paused = child.mActivityRecord != null ? child.mActivityRecord.paused : false;
inputWindowHandle.ownerPid = child.mSession.mPid;
@@ -280,7 +291,7 @@ final class InputMonitor {
inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures;
inputWindowHandle.displayId = child.getDisplayId();
- final Rect frame = child.getFrameLw();
+ final Rect frame = child.getFrame();
inputWindowHandle.frameLeft = frame.left;
inputWindowHandle.frameTop = frame.top;
inputWindowHandle.frameRight = frame.right;
@@ -463,9 +474,6 @@ final class InputMonitor {
mDisplayContent.forAllWindows(this,
true /* traverseTopToBottom */);
- if (mAddWallpaperInputConsumerHandle) {
- mWallpaperInputConsumer.show(mInputTransaction, 0);
- }
if (!mUpdateInputWindowsImmediately) {
mDisplayContent.getPendingTransaction().merge(mInputTransaction);
mDisplayContent.scheduleAnimation();
@@ -572,8 +580,7 @@ final class InputMonitor {
inputWindowHandle.layoutParamsType = type;
inputWindowHandle.dispatchingTimeoutMillis = 0; // it should never receive input
inputWindowHandle.visible = isVisible;
- inputWindowHandle.canReceiveKeys = false;
- inputWindowHandle.hasFocus = false;
+ inputWindowHandle.focusable = false;
inputWindowHandle.inputFeatures = INPUT_FEATURE_NO_INPUT_CHANNEL;
inputWindowHandle.scaleFactor = 1;
inputWindowHandle.layoutParamsFlags =
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index 3ffc26a7a8ad..5e7ed3f80e43 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import android.inputmethodservice.InputMethodService;
+import android.view.InsetsState;
import android.view.WindowInsets.Type.InsetsType;
/**
@@ -38,6 +39,13 @@ interface InsetsControlTarget {
}
/**
+ * @return The requested {@link InsetsState} of this target.
+ */
+ default InsetsState getRequestedInsetsState() {
+ return InsetsState.EMPTY;
+ }
+
+ /**
* Instructs the control target to show inset sources.
*
* @param types to specify which types of insets source window should be shown.
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index b7287e718bd6..18a25033b1e6 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -42,7 +42,6 @@ import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.ViewRootImpl;
-import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation;
import android.view.WindowInsetsAnimation.Bounds;
import android.view.WindowInsetsAnimationControlListener;
@@ -153,15 +152,13 @@ class InsetsPolicy {
return provider != null && provider.hasWindow() && !provider.getSource().isVisible();
}
- @InsetsType int showTransient(IntArray types) {
- @InsetsType int showingTransientTypes = 0;
+ void showTransient(@InternalInsetsType int[] types) {
boolean changed = false;
- for (int i = types.size() - 1; i >= 0; i--) {
- final int type = types.get(i);
+ for (int i = types.length - 1; i >= 0; i--) {
+ final @InternalInsetsType int type = types[i];
if (!isHidden(type)) {
continue;
}
- showingTransientTypes |= InsetsState.toPublicType(type);
if (mShowingTransientTypes.indexOf(type) != -1) {
continue;
}
@@ -189,7 +186,6 @@ class InsetsPolicy {
}
});
}
- return showingTransientTypes;
}
void hideTransient() {
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index d1eb79556d1d..e00c9e7ac38b 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -173,7 +173,7 @@ class InsetsSourceProvider {
// frame may not yet determined that server side doesn't think the window is ready to
// visible. (i.e. No surface, pending insets that were given during layout, etc..)
if (mServerVisible) {
- mTmpRect.set(mWin.getFrameLw());
+ mTmpRect.set(mWin.getFrame());
if (mFrameProvider != null) {
mFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin, mTmpRect);
} else {
@@ -185,14 +185,14 @@ class InsetsSourceProvider {
mSource.setFrame(mTmpRect);
if (mImeFrameProvider != null) {
- mImeOverrideFrame.set(mWin.getFrameLw());
+ mImeOverrideFrame.set(mWin.getFrame());
mImeFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin,
mImeOverrideFrame);
}
if (mWin.mGivenVisibleInsets.left != 0 || mWin.mGivenVisibleInsets.top != 0
|| mWin.mGivenVisibleInsets.right != 0 || mWin.mGivenVisibleInsets.bottom != 0) {
- mTmpRect.set(mWin.getFrameLw());
+ mTmpRect.set(mWin.getFrame());
mTmpRect.inset(mWin.mGivenVisibleInsets);
mSource.setVisibleFrame(mTmpRect);
} else {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 143fbb0fe48b..6882dc4ca151 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -821,7 +821,7 @@ public class RecentsAnimationController implements DeathRecipient {
: null;
if (targetAppMainWindow != null) {
targetAppMainWindow.getBounds(mTmpRect);
- inputWindowHandle.hasFocus = hasFocus;
+ inputWindowHandle.focusable = hasFocus;
inputWindowHandle.touchableRegion.set(mTmpRect);
return true;
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index aeaffd98f820..21e30ce0a495 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1106,14 +1106,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final WindowManager.LayoutParams attrs = w.mAttrs;
final int attrFlags = attrs.flags;
final boolean onScreen = w.isOnScreen();
- final boolean canBeSeen = w.isDisplayedLw();
+ final boolean canBeSeen = w.isDisplayed();
final int privateflags = attrs.privateFlags;
boolean displayHasContent = false;
ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON,
"handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w"
+ ".isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d",
- w, w.mHasSurface, onScreen, w.isDisplayedLw(), w.mAttrs.userActivityTimeout);
+ w, w.mHasSurface, onScreen, w.isDisplayed(), w.mAttrs.userActivityTimeout);
if (w.mHasSurface && onScreen) {
if (!syswin && w.mAttrs.userActivityTimeout >= 0 && mUserActivityTimeout < 0) {
mUserActivityTimeout = w.mAttrs.userActivityTimeout;
@@ -2716,7 +2716,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
+ " resumed=" + r.getStack().mResumedActivity + " pausing="
+ r.getStack().mPausingActivity + " for reason " + mDestroyAllActivitiesReason);
- r.destroyImmediately(true /* removeFromTask */, mDestroyAllActivitiesReason);
+ r.destroyImmediately(mDestroyAllActivitiesReason);
}
// Tries to put all activity stacks to sleep. Returns true if all stacks were
@@ -3124,7 +3124,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
FinishDisabledPackageActivitiesHelper mFinishDisabledPackageActivitiesHelper =
new FinishDisabledPackageActivitiesHelper();
class FinishDisabledPackageActivitiesHelper {
- private boolean mDidSomething;
private String mPackageName;
private Set<String> mFilterByClasses;
private boolean mDoit;
@@ -3132,11 +3131,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
private int mUserId;
private boolean mOnlyRemoveNoProcess;
private Task mLastTask;
- private ComponentName mHomeActivity;
+ private final ArrayList<ActivityRecord> mCollectedActivities = new ArrayList<>();
private void reset(String packageName, Set<String> filterByClasses,
boolean doit, boolean evenPersistent, int userId, boolean onlyRemoveNoProcess) {
- mDidSomething = false;
mPackageName = packageName;
mFilterByClasses = filterByClasses;
mDoit = doit;
@@ -3144,7 +3142,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mUserId = userId;
mOnlyRemoveNoProcess = onlyRemoveNoProcess;
mLastTask = null;
- mHomeActivity = null;
}
boolean process(String packageName, Set<String> filterByClasses,
@@ -3152,14 +3149,35 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
reset(packageName, filterByClasses, doit, evenPersistent, userId, onlyRemoveNoProcess);
final PooledFunction f = PooledLambda.obtainFunction(
- FinishDisabledPackageActivitiesHelper::processActivity, this,
+ FinishDisabledPackageActivitiesHelper::collectActivity, this,
PooledLambda.__(ActivityRecord.class));
forAllActivities(f);
f.recycle();
- return mDidSomething;
+
+ boolean didSomething = false;
+ final int size = mCollectedActivities.size();
+ // Keep the finishing order from top to bottom.
+ for (int i = 0; i < size; i++) {
+ final ActivityRecord r = mCollectedActivities.get(i);
+ if (mOnlyRemoveNoProcess) {
+ if (!r.hasProcess()) {
+ didSomething = true;
+ Slog.i(TAG, " Force removing " + r);
+ r.cleanUp(false /* cleanServices */, false /* setState */);
+ r.removeFromHistory("force-stop");
+ }
+ } else {
+ didSomething = true;
+ Slog.i(TAG, " Force finishing " + r);
+ r.finishIfPossible("force-stop", true /* oomAdj */);
+ }
+ }
+ mCollectedActivities.clear();
+
+ return didSomething;
}
- private boolean processActivity(ActivityRecord r) {
+ private boolean collectActivity(ActivityRecord r) {
final boolean sameComponent =
(r.packageName.equals(mPackageName) && (mFilterByClasses == null
|| mFilterByClasses.contains(r.mActivityComponent.getClassName())))
@@ -3176,26 +3194,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
return true;
}
- if (r.isActivityTypeHome()) {
- if (mHomeActivity != null && mHomeActivity.equals(r.mActivityComponent)) {
- Slog.i(TAG, "Skip force-stop again " + r);
- return false;
- } else {
- mHomeActivity = r.mActivityComponent;
- }
- }
- if (mOnlyRemoveNoProcess) {
- if (noProcess) {
- mDidSomething = true;
- Slog.i(TAG, " Force removing " + r);
- r.cleanUp(false /* cleanServices */, false /* setState */);
- r.removeFromHistory("force-stop");
- }
- } else {
- mDidSomething = true;
- Slog.i(TAG, " Force finishing " + r);
- r.finishIfPossible("force-stop", true /* oomAdj */);
- }
+ mCollectedActivities.add(r);
mLastTask = r.getTask();
}
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 3c8036d4e3b6..25732e7f0d99 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -101,7 +101,6 @@ class ScreenRotationAnimation {
private final Transformation mRotateExitTransformation = new Transformation();
private final Transformation mRotateEnterTransformation = new Transformation();
// Complete transformations being applied.
- private final Transformation mEnterTransformation = new Transformation();
private final Matrix mSnapshotInitialMatrix = new Matrix();
private final WindowManagerService mService;
/** Only used for custom animations and not screen rotation. */
@@ -309,8 +308,6 @@ class ScreenRotationAnimation {
pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println();
pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation);
pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println();
- pw.print(prefix); pw.print("mEnterTransformation=");
- mEnterTransformation.printShortString(pw); pw.println();
pw.print(prefix); pw.print("mSnapshotInitialMatrix=");
mSnapshotInitialMatrix.dump(pw); pw.println();
pw.print(prefix); pw.print("mForceDefaultOrientation="); pw.print(mForceDefaultOrientation);
@@ -508,10 +505,6 @@ class ScreenRotationAnimation {
return mCurRotation != mOriginalRotation;
}
- public Transformation getEnterTransformation() {
- return mEnterTransformation;
- }
-
/**
* Utility class that runs a {@link ScreenRotationAnimation} on the {@link
* SurfaceAnimationRunner}.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 0529abf89f6e..e77a53582e09 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -783,7 +783,7 @@ class Task extends WindowContainer<WindowContainer> {
* taskAppeared callback, and emit a taskRemoved callback when the Task is vanished.
*/
ITaskOrganizer mTaskOrganizer;
- private int mLastTaskOrganizerWindowingMode = -1;
+
/**
* Prevent duplicate calls to onTaskAppeared.
*/
@@ -798,6 +798,7 @@ class Task extends WindowContainer<WindowContainer> {
* organizer for ordering purposes.</li>
* </ul>
*/
+ @VisibleForTesting
boolean mCreatedByOrganizer;
/**
@@ -2788,8 +2789,16 @@ class Task extends WindowContainer<WindowContainer> {
// For calculating screen layout, we need to use the non-decor inset screen area for the
// calculation for compatibility reasons, i.e. screen area without system bars that
// could never go away in Honeycomb.
- final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
- final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
+ int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
+ int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
+ // Use overrides if provided. If both overrides are provided, mTmpNonDecorBounds is
+ // undefined so it can't be used.
+ if (inOutConfig.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
+ compatScreenWidthDp = inOutConfig.screenWidthDp;
+ }
+ if (inOutConfig.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+ compatScreenHeightDp = inOutConfig.screenHeightDp;
+ }
// Reducing the screen layout starting from its parent config.
inOutConfig.screenLayout = computeScreenLayoutOverride(parentConfig.screenLayout,
compatScreenWidthDp, compatScreenHeightDp);
@@ -3820,7 +3829,10 @@ class Task extends WindowContainer<WindowContainer> {
@Override
boolean fillsParent() {
- return matchParentBounds();
+ // From the perspective of policy, we still want to report that this task fills parent
+ // in fullscreen windowing mode even it doesn't match parent bounds because there will be
+ // letterbox around its real content.
+ return getWindowingMode() == WINDOWING_MODE_FULLSCREEN || matchParentBounds();
}
@Override
@@ -4820,19 +4832,18 @@ class Task extends WindowContainer<WindowContainer> {
return false;
}
- ITaskOrganizer previousOrganizer = mTaskOrganizer;
+ ITaskOrganizer prevOrganizer = mTaskOrganizer;
// Update the new task organizer before calling sendTaskVanished since it could result in
// a new SurfaceControl getting created that would notify the old organizer about it.
mTaskOrganizer = organizer;
// Let the old organizer know it has lost control.
- sendTaskVanished(previousOrganizer);
+ sendTaskVanished(prevOrganizer);
if (mTaskOrganizer != null) {
sendTaskAppeared();
} else {
// No longer managed by any organizer.
mTaskAppearedSent = false;
- mLastTaskOrganizerWindowingMode = -1;
setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, false /* set */);
if (mCreatedByOrganizer) {
removeImmediately();
@@ -4853,29 +4864,16 @@ class Task extends WindowContainer<WindowContainer> {
*/
boolean updateTaskOrganizerState(boolean forceUpdate) {
if (!isRootTask()) {
- final boolean result = setTaskOrganizer(null);
- mLastTaskOrganizerWindowingMode = -1;
- return result;
+ return setTaskOrganizer(null);
}
final int windowingMode = getWindowingMode();
- if (!forceUpdate && windowingMode == mLastTaskOrganizerWindowingMode) {
- // If our windowing mode hasn't actually changed, then just stick
- // with our old organizer. This lets us implement the semantic
- // where SysUI can continue to manage it's old tasks
- // while CTS temporarily takes over the registration.
+ final TaskOrganizerController controller = mWmService.mAtmService.mTaskOrganizerController;
+ final ITaskOrganizer organizer = controller.getTaskOrganizer(windowingMode);
+ if (!forceUpdate && mTaskOrganizer == organizer) {
return false;
}
- /*
- * Different windowing modes may be managed by different task organizers. If
- * getTaskOrganizer returns null, we still call setTaskOrganizer to
- * make sure we clear it.
- */
- final ITaskOrganizer org =
- mWmService.mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode);
- final boolean result = setTaskOrganizer(org);
- mLastTaskOrganizerWindowingMode = org != null ? windowingMode : -1;
- return result;
+ return setTaskOrganizer(organizer);
}
@Override
@@ -6192,10 +6190,6 @@ class Task extends WindowContainer<WindowContainer> {
next.setState(RESUMED, "resumeTopActivityInnerLocked");
- next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
- true /* activityChange */, true /* updateOomAdj */,
- true /* addPendingTopUid */);
-
// Have the window manager re-evaluate the orientation of
// the screen based on the new activity order.
boolean notUpdated = true;
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 32511108836e..6550167683a0 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1489,9 +1489,13 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return stack == getTopStack();
}
- boolean isTopNotPinnedStack(Task stack) {
+ boolean isTopNotFinishNotPinnedStack(Task stack) {
for (int i = getStackCount() - 1; i >= 0; --i) {
final Task current = getStackAt(i);
+ final ActivityRecord topAct = current.getTopNonFinishingActivity();
+ if (topAct == null) {
+ continue;
+ }
if (!current.inPinnedWindowingMode()) {
return current == stack;
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 04d134c3649d..f8465ddc02a2 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -20,6 +20,8 @@ import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFIGS;
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS;
@@ -35,7 +37,6 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
-import android.util.SparseArray;
import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
@@ -46,9 +47,12 @@ import com.android.internal.util.ArrayUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Set;
import java.util.WeakHashMap;
import java.util.function.Consumer;
@@ -58,7 +62,6 @@ import java.util.function.Consumer;
*/
class TaskOrganizerController extends ITaskOrganizerController.Stub {
private static final String TAG = "TaskOrganizerController";
- private static final LinkedList<IBinder> EMPTY_LIST = new LinkedList<>();
/**
* Masks specifying which configurations are important to report back to an organizer when
@@ -67,6 +70,16 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
private static final int REPORT_CONFIGS = CONTROLLABLE_CONFIGS;
private static final int REPORT_WINDOW_CONFIGS = CONTROLLABLE_WINDOW_CONFIGS;
+ // The set of modes that are currently supports
+ // TODO: Remove once the task organizer can support all modes
+ @VisibleForTesting
+ static final int[] SUPPORTED_WINDOWING_MODES = {
+ WINDOWING_MODE_PINNED,
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
+ WINDOWING_MODE_MULTI_WINDOW,
+ };
+
private final WindowManagerGlobalLock mGlobalLock;
private class DeathRecipient implements IBinder.DeathRecipient {
@@ -233,9 +246,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
void dispose() {
// Move organizer from managing specific windowing modes
- for (int i = mTaskOrganizersForWindowingMode.size() - 1; i >= 0; --i) {
- mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.getBinder());
- }
+ mTaskOrganizers.remove(mOrganizer.mTaskOrganizer);
// Update tasks currently managed by this organizer to the next one available if
// possible.
@@ -257,8 +268,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
}
- private final SparseArray<LinkedList<IBinder>> mTaskOrganizersForWindowingMode =
- new SparseArray<>();
+ // List of task organizers by priority
+ private final LinkedList<ITaskOrganizer> mTaskOrganizers = new LinkedList<>();
private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
@@ -285,59 +296,28 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
public void setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer) {
mDeferTaskOrgCallbacksConsumer = consumer;
}
-
/**
- * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
- * If there was already a TaskOrganizer for this windowing mode it will be evicted
- * but will continue to organize it's existing tasks.
+ * Register a TaskOrganizer to manage tasks as they enter the a supported windowing mode.
*/
@Override
- public void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) {
- if (windowingMode == WINDOWING_MODE_PINNED) {
- if (!mService.mSupportsPictureInPicture) {
- throw new UnsupportedOperationException("Picture in picture is not supported on "
- + "this device");
- }
- } else if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
- if (!mService.mSupportsSplitScreenMultiWindow) {
- throw new UnsupportedOperationException("Split-screen is not supported on this "
- + "device");
- }
- } else if (windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
- if (!mService.mSupportsMultiWindow) {
- throw new UnsupportedOperationException("Multi-window is not supported on this "
- + "device");
- }
- } else {
- throw new UnsupportedOperationException("As of now only Pinned/Split/Multiwindow"
- + " windowing modes are supported for registerTaskOrganizer");
- }
+ public void registerTaskOrganizer(ITaskOrganizer organizer) {
enforceStackPermission("registerTaskOrganizer()");
final int uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- if (getTaskOrganizer(windowingMode) != null) {
- Slog.w(TAG, "Task organizer already exists for windowing mode: "
- + windowingMode);
- }
-
- LinkedList<IBinder> orgs = mTaskOrganizersForWindowingMode.get(windowingMode);
- if (orgs == null) {
- orgs = new LinkedList<>();
- mTaskOrganizersForWindowingMode.put(windowingMode, orgs);
- }
- orgs.add(organizer.asBinder());
- if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) {
- mTaskOrganizerStates.put(organizer.asBinder(),
- new TaskOrganizerState(organizer, uid));
- }
-
- mService.mRootWindowContainer.forAllTasks((task) -> {
- if (task.getWindowingMode() == windowingMode) {
- task.updateTaskOrganizerState(true /* forceUpdate */);
+ for (int winMode : SUPPORTED_WINDOWING_MODES) {
+ if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) {
+ mTaskOrganizers.add(organizer);
+ mTaskOrganizerStates.put(organizer.asBinder(),
+ new TaskOrganizerState(organizer, uid));
}
- });
+ mService.mRootWindowContainer.forAllTasks((task) -> {
+ if (task.getWindowingMode() == winMode) {
+ task.updateTaskOrganizerState(true /* forceUpdate */);
+ }
+ });
+ }
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -362,17 +342,22 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
}
+ /**
+ * @return the task organizer key for a given windowing mode.
+ */
ITaskOrganizer getTaskOrganizer(int windowingMode) {
- final IBinder organizer =
- mTaskOrganizersForWindowingMode.get(windowingMode, EMPTY_LIST).peekLast();
- if (organizer == null) {
- return null;
- }
- final TaskOrganizerState state = mTaskOrganizerStates.get(organizer);
- if (state == null) {
- return null;
+ return isSupportedWindowingMode(windowingMode)
+ ? mTaskOrganizers.peekLast()
+ : null;
+ }
+
+ private boolean isSupportedWindowingMode(int winMode) {
+ for (int i = 0; i < SUPPORTED_WINDOWING_MODES.length; i++) {
+ if (SUPPORTED_WINDOWING_MODES[i] == winMode) {
+ return true;
+ }
}
- return state.mOrganizer.mTaskOrganizer;
+ return false;
}
void onTaskAppeared(ITaskOrganizer organizer, Task task) {
@@ -458,6 +443,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|| mTmpTaskInfo.topActivityType != lastInfo.topActivityType
|| mTmpTaskInfo.isResizeable != lastInfo.isResizeable
|| mTmpTaskInfo.pictureInPictureParams != lastInfo.pictureInPictureParams
+ || mTmpTaskInfo.getConfiguration().windowConfiguration.getWindowingMode()
+ != lastInfo.getConfiguration().windowConfiguration.getWindowingMode()
|| !TaskDescription.equals(mTmpTaskInfo.taskDescription, lastInfo.taskDescription);
if (!changed) {
int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration);
@@ -655,18 +642,19 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
final String innerPrefix = prefix + " ";
pw.print(prefix); pw.println("TaskOrganizerController:");
pw.print(innerPrefix); pw.println("Per windowing mode:");
- for (int i = 0; i < mTaskOrganizersForWindowingMode.size(); i++) {
- final int windowingMode = mTaskOrganizersForWindowingMode.keyAt(i);
- final List<IBinder> taskOrgs = mTaskOrganizersForWindowingMode.valueAt(i);
+ for (int i = 0; i < SUPPORTED_WINDOWING_MODES.length; i++) {
+ final int windowingMode = SUPPORTED_WINDOWING_MODES[i];
pw.println(innerPrefix + " "
+ WindowConfiguration.windowingModeToString(windowingMode) + ":");
- for (int j = 0; j < taskOrgs.size(); j++) {
- final TaskOrganizerState state = mTaskOrganizerStates.get(taskOrgs.get(j));
+ for (final TaskOrganizerState state : mTaskOrganizerStates.values()) {
final ArrayList<Task> tasks = state.mOrganizedTasks;
pw.print(innerPrefix + " ");
pw.println(state.mOrganizer.mTaskOrganizer + " uid=" + state.mUid + ":");
for (int k = 0; k < tasks.size(); k++) {
- pw.println(innerPrefix + " " + tasks.get(k));
+ final Task task = tasks.get(k);
+ if (windowingMode == task.getWindowingMode()) {
+ pw.println(innerPrefix + " " + task);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index a66cd846e8be..f32781a8fcb8 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -242,8 +242,8 @@ class TaskPositioner implements IBinder.DeathRecipient {
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mDragWindowHandle.visible = true;
- mDragWindowHandle.canReceiveKeys = false;
- mDragWindowHandle.hasFocus = true;
+ // When dragging the window around, we do not want to steal focus for the window.
+ mDragWindowHandle.focusable = false;
mDragWindowHandle.hasWallpaper = false;
mDragWindowHandle.paused = false;
mDragWindowHandle.ownerPid = Process.myPid();
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index dbbb7ff69b3b..e3112efdead2 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -483,7 +483,7 @@ class TaskSnapshotController {
final InsetsState insetsState =
new InsetsState(insetsPolicy.getInsetsForDispatch(mainWindow));
mergeInsetsSources(insetsState, mainWindow.getRequestedInsetsState());
- final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrameLw(), insetsState);
+ final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrame(), insetsState);
final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
attrs.privateFlags, attrs.systemUiVisibility, task.getTaskDescription(),
mHighResTaskSnapshotScale, insetsState);
diff --git a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
index 61e9e5082d17..5e81e4008680 100644
--- a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
+++ b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
@@ -24,8 +24,6 @@ import android.annotation.NonNull;
import android.util.ArrayMap;
import android.util.Slog;
-import com.android.server.wm.WindowManagerService.H;
-
import java.io.PrintWriter;
/**
@@ -102,7 +100,13 @@ class UnknownAppVisibilityController {
if (DEBUG_UNKNOWN_APP_VISIBILITY) {
Slog.d(TAG, "App launched activity=" + activity);
}
- mUnknownApps.put(activity, UNKNOWN_STATE_WAITING_RESUME);
+ // If the activity was started with launchTaskBehind, the lifecycle will goes to paused
+ // directly, and the process will pass onResume, so we don't need to waiting resume for it.
+ if (!activity.mLaunchTaskBehind) {
+ mUnknownApps.put(activity, UNKNOWN_STATE_WAITING_RESUME);
+ } else {
+ mUnknownApps.put(activity, UNKNOWN_STATE_WAITING_RELAYOUT);
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 6e00ab4939fa..ce138674cb93 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -308,7 +308,7 @@ class WallpaperController {
float defaultWallpaperX = wallpaperWin.isRtl() ? 1f : 0f;
float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : defaultWallpaperX;
float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
- int availw = wallpaperWin.getFrameLw().right - wallpaperWin.getFrameLw().left - dw;
+ int availw = wallpaperWin.getFrame().right - wallpaperWin.getFrame().left - dw;
int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0;
if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
offset += mLastWallpaperDisplayOffsetX;
@@ -323,7 +323,7 @@ class WallpaperController {
float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f;
float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f;
- int availh = wallpaperWin.getFrameLw().bottom - wallpaperWin.getFrameLw().top - dh;
+ int availh = wallpaperWin.getFrame().bottom - wallpaperWin.getFrame().top - dh;
offset = availh > 0 ? -(int)(availh * wpy + .5f) : 0;
if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
offset += mLastWallpaperDisplayOffsetY;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index cd222a97f4d9..c45ccb6e17e3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+import static android.Manifest.permission.INPUT_CONSUMER;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.MANAGE_APP_TOKENS;
@@ -929,7 +930,7 @@ public class WindowManagerService extends IWindowManager.Stub
private void setShadowRenderer() {
mRenderShadowsInCompositor = Settings.Global.getInt(mContext.getContentResolver(),
- DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 0) != 0;
+ DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 1) != 0;
}
PowerManager mPowerManager;
@@ -1847,7 +1848,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
// We use the visible frame, because we want the animation to morph the window from what
// was visible to the user to the final destination of the new window.
- Rect frame = replacedWindow.getVisibleFrameLw();
+ Rect frame = replacedWindow.getVisibleFrame();
// We treat this as if this activity was opening, so we can trigger the app transition
// animation and piggy-back on existing transition animation infrastructure.
final DisplayContent dc = activity.getDisplayContent();
@@ -2068,7 +2069,7 @@ public class WindowManagerService extends IWindowManager.Stub
outDisplayFrame.setEmpty();
return;
}
- outDisplayFrame.set(win.getDisplayFrameLw());
+ outDisplayFrame.set(win.getDisplayFrame());
if (win.inSizeCompatMode()) {
outDisplayFrame.scale(win.mInvGlobalScale);
}
@@ -2388,7 +2389,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (displayPolicy.areSystemBarsForcedShownLw(win)) {
result |= WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
}
- if (!win.isGoneForLayoutLw()) {
+ if (!win.isGoneForLayout()) {
win.mResizedWhileGone = false;
}
@@ -2418,7 +2419,7 @@ public class WindowManagerService extends IWindowManager.Stub
win.getInsetsForRelayout(outContentInsets, outVisibleInsets,
outStableInsets);
outCutout.set(win.getWmDisplayCutout().getDisplayCutout());
- outBackdropFrame.set(win.getBackdropFrame(win.getFrameLw()));
+ outBackdropFrame.set(win.getBackdropFrame(win.getFrame()));
outInsetsState.set(win.getInsetsState(), win.isClientLocal());
if (DEBUG) {
Slog.v(TAG_WM, "Relayout given client " + client.asBinder()
@@ -2882,11 +2883,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public WindowManagerPolicy.WindowState getInputMethodWindowLw() {
- return mRoot.getCurrentInputMethodWindow();
- }
-
- @Override
public void notifyKeyguardTrustedChanged() {
mAtmInternal.notifyKeyguardTrustedChanged();
}
@@ -5480,7 +5476,7 @@ public class WindowManagerService extends IWindowManager.Stub
// Window has been removed or hidden; no draw will now happen, so stop waiting.
ProtoLog.w(WM_DEBUG_SCREEN_ON, "Aborted waiting for drawn: %s", win);
container.mWaitingForDrawn.remove(win);
- } else if (win.hasDrawnLw()) {
+ } else if (win.hasDrawn()) {
// Window is now drawn (and shown).
ProtoLog.d(WM_DEBUG_SCREEN_ON, "Window drawn win=%s", win);
container.mWaitingForDrawn.remove(win);
@@ -5861,6 +5857,11 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void createInputConsumer(IBinder token, String name, int displayId,
InputChannel inputChannel) {
+ if (!mAtmInternal.isCallerRecents(Binder.getCallingUid())
+ && mContext.checkCallingOrSelfPermission(INPUT_CONSUMER) != PERMISSION_GRANTED) {
+ throw new SecurityException("createInputConsumer requires INPUT_CONSUMER permission");
+ }
+
synchronized (mGlobalLock) {
DisplayContent display = mRoot.getDisplayContent(displayId);
if (display != null) {
@@ -5872,6 +5873,11 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public boolean destroyInputConsumer(String name, int displayId) {
+ if (!mAtmInternal.isCallerRecents(Binder.getCallingUid())
+ && mContext.checkCallingOrSelfPermission(INPUT_CONSUMER) != PERMISSION_GRANTED) {
+ throw new SecurityException("destroyInputConsumer requires INPUT_CONSUMER permission");
+ }
+
synchronized (mGlobalLock) {
DisplayContent display = mRoot.getDisplayContent(displayId);
if (display != null) {
@@ -7345,7 +7351,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized (mGlobalLock) {
WindowState windowState = mWindowMap.get(token);
if (windowState != null) {
- outBounds.set(windowState.getFrameLw());
+ outBounds.set(windowState.getFrame());
} else {
outBounds.setEmpty();
}
@@ -8065,8 +8071,7 @@ public class WindowManagerService extends IWindowManager.Stub
h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags;
h.layoutParamsType = type;
h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- h.canReceiveKeys = false;
- h.hasFocus = false;
+ h.focusable = false;
h.hasWallpaper = false;
h.paused = false;
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index c714eeb92e68..bb9cf2e2ac05 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -941,7 +941,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
final ActivityRecord r = candidates.remove(0);
if (DEBUG_RELEASE) Slog.v(TAG_RELEASE, "Destroying " + r
+ " in state " + r.getState() + " for reason " + reason);
- r.destroyImmediately(true /*removeFromApp*/, reason);
+ r.destroyImmediately(reason);
--maxRelease;
} while (maxRelease > 0);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 49e623d8dd11..9ff33b18cb89 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -728,7 +728,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* @return The insets state as requested by the client, i.e. the dispatched insets state
* for which the visibilities are overridden with what the client requested.
*/
- InsetsState getRequestedInsetsState() {
+ @Override
+ public InsetsState getRequestedInsetsState() {
return mRequestedInsetsState;
}
@@ -1008,8 +1009,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
getDisplayContent().reapplyMagnificationSpec();
}
- @Override
- public int getOwningUid() {
+ /** Returns the uid of the app that owns this window. */
+ int getOwningUid() {
return mOwnerUid;
}
@@ -1023,8 +1024,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mOwnerCanAddInternalSystemWindow;
}
- @Override
- public boolean canAcquireSleepToken() {
+ /**
+ * Returns {@code true} if the window owner has the permission to acquire a sleep token when
+ * it's visible. That is, they have the permission
+ * {@link androidManifest.permission#DEVICE_POWER}.
+ */
+ boolean canAcquireSleepToken() {
return mSession.mCanAcquireSleepToken;
}
@@ -1045,7 +1050,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
void computeFrame(DisplayFrames displayFrames) {
getLayoutingWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
- computeFrameLw();
+ computeFrame();
// Update the source frame to provide insets to other windows during layout. If the
// simulated frames exist, then this is not computing a stable result so just skip.
if (mControllableInsetProvider != null && mSimulatedWindowFrames == null) {
@@ -1053,8 +1058,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- @Override
- public void computeFrameLw() {
+ /**
+ * Perform standard frame computation. The result can be obtained with getFrame() if so desired.
+ */
+ void computeFrame() {
if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
// This window is being replaced and either already got information that it's being
// removed or we are still waiting for some information. Because of this we don't
@@ -1282,32 +1289,41 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- @Override
- public Rect getFrameLw() {
+ /** Retrieves the current frame of the window that the application sees. */
+ Rect getFrame() {
return mWindowFrames.mFrame;
}
/** Accessor for testing */
- Rect getRelativeFrameLw() {
+ Rect getRelativeFrame() {
return mWindowFrames.mRelFrame;
}
- @Override
- public Rect getDisplayFrameLw() {
+ /** Retrieves the frame of the display that this window was last laid out in. */
+ Rect getDisplayFrame() {
return mWindowFrames.mDisplayFrame;
}
- @Override
- public Rect getContentFrameLw() {
+ /**
+ * Retrieves the frame of the content area that this window was last laid out in. This is the
+ * area in which the content of the window should be placed. It will be smaller than the display
+ * frame to account for screen decorations such as a status bar or soft keyboard.
+ */
+ Rect getContentFrame() {
return mWindowFrames.mContentFrame;
}
- @Override
- public Rect getVisibleFrameLw() {
+ /**
+ * Retrieves the frame of the visible area that this window was last laid out in. This is the
+ * area of the screen in which the window will actually be fully visible. It will be smaller
+ * than the content frame to account for transient UI elements blocking it such as an input
+ * method's candidates UI.
+ */
+ Rect getVisibleFrame() {
return mWindowFrames.mVisibleFrame;
}
- Rect getStableFrameLw() {
+ Rect getStableFrame() {
return mWindowFrames.mStableFrame;
}
@@ -1336,32 +1352,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
@Override
- public boolean getGivenInsetsPendingLw() {
- return mGivenInsetsPending;
- }
-
- @Override
- public Rect getGivenContentInsetsLw() {
- return mGivenContentInsets;
- }
-
- @Override
- public Rect getGivenVisibleInsetsLw() {
- return mGivenVisibleInsets;
- }
-
- @Override
public WindowManager.LayoutParams getAttrs() {
return mAttrs;
}
- @Override
- public int getSystemUiVisibility() {
+ /** Retrieves the current system UI visibility flags associated with this window. */
+ int getSystemUiVisibility() {
return mSystemUiVisibility;
}
- @Override
- public int getSurfaceLayer() {
+ /** Gets the layer at which this window's surface will be Z-ordered. */
+ int getSurfaceLayer() {
return mLayer;
}
@@ -1375,8 +1376,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mActivityRecord != null ? mActivityRecord.appToken : null;
}
- @Override
- public boolean isVoiceInteraction() {
+ /** Returns true if this window is participating in voice interaction. */
+ boolean isVoiceInteraction() {
return mActivityRecord != null && mActivityRecord.mVoiceInteraction;
}
@@ -1390,7 +1391,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
void updateResizingWindowIfNeeded() {
final WindowStateAnimator winAnimator = mWinAnimator;
- if (!mHasSurface || getDisplayContent().mLayoutSeq != mLayoutSeq || isGoneForLayoutLw()) {
+ if (!mHasSurface || getDisplayContent().mLayoutSeq != mLayoutSeq || isGoneForLayout()) {
return;
}
@@ -1463,7 +1464,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mWmService.mResizingWindows.add(this);
}
} else if (getOrientationChanging()) {
- if (isDrawnLw()) {
+ if (isDrawn()) {
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Orientation not waiting for draw in %s, surfaceController %s", this,
winAnimator.mSurfaceController);
@@ -1638,9 +1639,16 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
: DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
}
- @Override
- public boolean hasAppShownWindows() {
- return mActivityRecord != null && (mActivityRecord.firstWindowDrawn || mActivityRecord.startingDisplayed);
+ /**
+ * Returns true if, at any point, the application token associated with this window has actually
+ * displayed any windows. This is most useful with the "starting up" window to determine if any
+ * windows were displayed when it is closed.
+ *
+ * @return {@code true} if one or more windows have been displayed, else false.
+ */
+ boolean hasAppShownWindows() {
+ return mActivityRecord != null
+ && (mActivityRecord.firstWindowDrawn || mActivityRecord.startingDisplayed);
}
boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
@@ -1662,7 +1670,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
boolean hasContentToDisplay() {
- if (!mAppFreezing && isDrawnLw() && (mViewVisibility == View.VISIBLE
+ if (!mAppFreezing && isDrawn() && (mViewVisibility == View.VISIBLE
|| (isAnimating(TRANSITION | PARENTS)
&& !getDisplayContent().mAppTransition.isTransitionSet()))) {
return true;
@@ -1850,10 +1858,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* Like isOnScreen, but returns false if the surface hasn't yet
* been drawn.
*/
- @Override
- public boolean isDisplayedLw() {
+ boolean isDisplayed() {
final ActivityRecord atoken = mActivityRecord;
- return isDrawnLw() && isVisibleByPolicy()
+ return isDrawn() && isVisibleByPolicy()
&& ((!isParentWindowHidden() && (atoken == null || atoken.mVisibleRequested))
|| isAnimating(TRANSITION | PARENTS));
}
@@ -1866,8 +1873,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return isAnimating(TRANSITION | PARENTS);
}
- @Override
- public boolean isGoneForLayoutLw() {
+ /** Returns {@code true} if this window considered to be gone for purposes of layout. */
+ boolean isGoneForLayout() {
final ActivityRecord atoken = mActivityRecord;
return mViewVisibility == View.GONE
|| !mRelayoutCalled
@@ -1894,11 +1901,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
/**
- * Returns true if the window has a surface that it has drawn a
- * complete UI in to.
+ * Returns true if the window has a surface that it has drawn a complete UI in to. Note that
+ * this is different from {@link #hasDrawn()} in that it also returns true if the window is
+ * READY_TO_SHOW, but was not yet promoted to HAS_DRAWN.
*/
- @Override
- public boolean isDrawnLw() {
+ boolean isDrawn() {
return mHasSurface && !mDestroying &&
(mWinAnimator.mDrawState == READY_TO_SHOW || mWinAnimator.mDrawState == HAS_DRAWN);
}
@@ -1913,7 +1920,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// to determine if it's occluding apps.
return ((!mIsWallpaper && mAttrs.format == PixelFormat.OPAQUE)
|| (mIsWallpaper && mWallpaperVisible))
- && isDrawnLw() && !isAnimating(TRANSITION | PARENTS);
+ && isDrawn() && !isAnimating(TRANSITION | PARENTS);
}
/** @see WindowManagerInternal#waitForAllWindowsDrawn */
@@ -1928,7 +1935,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return;
}
if (mAttrs.type == TYPE_APPLICATION_STARTING) {
- if (isDrawnLw()) {
+ if (isDrawn()) {
// Unnecessary to redraw a drawn starting window.
return;
}
@@ -2015,11 +2022,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
void onResize() {
final ArrayList<WindowState> resizingWindows = mWmService.mResizingWindows;
- if (mHasSurface && !isGoneForLayoutLw() && !resizingWindows.contains(this)) {
+ if (mHasSurface && !isGoneForLayout() && !resizingWindows.contains(this)) {
ProtoLog.d(WM_DEBUG_RESIZE, "onResize: Resizing %s", this);
resizingWindows.add(this);
}
- if (isGoneForLayoutLw()) {
+ if (isGoneForLayout()) {
mResizedWhileGone = true;
}
@@ -2057,10 +2064,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// animating... let's do something.
final int left = mWindowFrames.mFrame.left;
final int top = mWindowFrames.mFrame.top;
+
+ // During the transition from pip to fullscreen, the activity windowing mode is set to
+ // fullscreen at the beginning while the task is kept in pinned mode. Skip the move
+ // animation in such case since the transition is handled in SysUI.
+ final boolean hasMovementAnimation = getTask() == null
+ ? getWindowConfiguration().hasMovementAnimations()
+ : getTask().getWindowConfiguration().hasMovementAnimations();
if (mToken.okToAnimate()
&& (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
&& !isDragResizing()
- && getWindowConfiguration().hasMovementAnimations()
+ && hasMovementAnimation
&& !mWinAnimator.mLastHidden
&& !mSeamlesslyRotated) {
startMoveAnimation(left, top);
@@ -2506,7 +2520,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
/** Returns true if the replacement window was removed. */
boolean removeReplacedWindowIfNeeded(WindowState replacement) {
- if (mWillReplaceWindow && mReplacementWindow == replacement && replacement.hasDrawnLw()) {
+ if (mWillReplaceWindow && mReplacementWindow == replacement && replacement.hasDrawn()) {
replacement.mSkipEnterAnimationForSeamlessReplacement = false;
removeReplacedWindow();
return true;
@@ -2740,7 +2754,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mLayoutNeeded = true;
}
- if (isDrawnLw() && mToken.okToAnimate()) {
+ if (isDrawn() && mToken.okToAnimate()) {
mWinAnimator.applyEnterAnimationLocked();
}
}
@@ -2865,8 +2879,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return getWindowConfiguration().keepVisibleDeadAppWindowOnScreen();
}
- @Override
- public boolean canReceiveKeys() {
+ /** Returns {@code true} if this window desires key events. */
+ boolean canReceiveKeys() {
return canReceiveKeys(false /* fromUserTouch */);
}
@@ -2915,8 +2929,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
&& recentsAnimationController.shouldApplyInputConsumer(mActivityRecord);
}
- @Override
- public boolean hasDrawnLw() {
+ /**
+ * Returns {@code true} if this window has been shown on screen at some time in the past.
+ *
+ * @deprecated Use {@link #isDrawnLw} or any of the other drawn/visibility methods.
+ */
+ @Deprecated
+ boolean hasDrawn() {
return mWinAnimator.mDrawState == WindowStateAnimator.HAS_DRAWN;
}
@@ -3150,8 +3169,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- @Override
- public boolean isAlive() {
+ /** Checks whether the process hosting this window is currently alive. */
+ boolean isAlive() {
return mClient.asBinder().isBinderAlive();
}
@@ -3331,16 +3350,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mLastExclusionLogUptimeMillis[EXCLUSION_RIGHT] = now;
}
- @Override
- public boolean isDefaultDisplay() {
- final DisplayContent displayContent = getDisplayContent();
- if (displayContent == null) {
- // Only a window that was on a non-default display can be detached from it.
- return false;
- }
- return displayContent.isDefaultDisplay;
- }
-
/** @return {@code true} if this window can be shown to all users. */
boolean showForAllUsers() {
@@ -3400,10 +3409,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// All window frames that are fullscreen extend above status bar, but some don't extend
// below navigation bar. Thus, check for display frame for top/left and stable frame for
// bottom right.
- if (win.getFrameLw().left <= win.getDisplayFrameLw().left
- && win.getFrameLw().top <= win.getDisplayFrameLw().top
- && win.getFrameLw().right >= win.getStableFrameLw().right
- && win.getFrameLw().bottom >= win.getStableFrameLw().bottom) {
+ if (win.getFrame().left <= win.getDisplayFrame().left
+ && win.getFrame().top <= win.getDisplayFrame().top
+ && win.getFrame().right >= win.getStableFrame().right
+ && win.getFrame().bottom >= win.getStableFrame().bottom) {
// Is a fullscreen window, like the clock alarm. Show to everyone.
return true;
}
@@ -3561,6 +3570,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
void reportResized() {
+ // If the activity is scheduled to relaunch, skip sending the resized to ViewRootImpl now
+ // since it will be destroyed anyway. This also prevents the client from receiving
+ // windowing mode change before it is destroyed.
+ if (mActivityRecord != null && mActivityRecord.isRelaunching()) {
+ return;
+ }
+
if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.reportResized_" + getWindowTag());
}
@@ -3766,11 +3782,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* is transitioning into/out-of fullscreen. */
boolean isLetterboxedAppWindow() {
return !inMultiWindowMode() && !matchesDisplayBounds()
- || isLetterboxedForDisplayCutoutLw();
+ || isLetterboxedForDisplayCutout();
}
- @Override
- public boolean isLetterboxedForDisplayCutoutLw() {
+ /** Returns {@code true} if the window is letterboxed for the display cutout. */
+ boolean isLetterboxedForDisplayCutout() {
if (mActivityRecord == null) {
// Only windows with an ActivityRecord are letterboxed.
return false;
@@ -3874,7 +3890,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// background.
return (getDisplayContent().mDividerControllerLocked.isResizing()
|| mActivityRecord != null && !mActivityRecord.mFrozenBounds.isEmpty()) &&
- !task.inFreeformWindowingMode() && !isGoneForLayoutLw();
+ !task.inFreeformWindowingMode() && !isGoneForLayout();
}
@@ -4290,7 +4306,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
private boolean isParentWindowGoneForLayout() {
final WindowState parent = getParentWindow();
- return parent != null && parent.isGoneForLayoutLw();
+ return parent != null && parent.isGoneForLayout();
}
void setWillReplaceWindow(boolean animate) {
@@ -4403,8 +4419,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return null;
}
- @Override
- public int getRotationAnimationHint() {
+ int getRotationAnimationHint() {
if (mActivityRecord != null) {
return mActivityRecord.mRotationAnimationHint;
} else {
@@ -4860,7 +4875,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
boolean hasVisibleNotDrawnWallpaper() {
- if (mWallpaperVisible && !isDrawnLw()) {
+ if (mWallpaperVisible && !isDrawn()) {
return true;
}
for (int j = mChildren.size() - 1; j >= 0; --j) {
@@ -4884,9 +4899,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return;
}
if (DEBUG_VISIBILITY) {
- Slog.v(TAG, "Win " + this + ": isDrawn=" + isDrawnLw()
+ Slog.v(TAG, "Win " + this + ": isDrawn=" + isDrawn()
+ ", animating=" + isAnimating(TRANSITION | PARENTS));
- if (!isDrawnLw()) {
+ if (!isDrawn()) {
Slog.v(TAG, "Not displayed: s=" + mWinAnimator.mSurfaceController
+ " pv=" + isVisibleByPolicy()
+ " mDrawState=" + mWinAnimator.mDrawState
@@ -4897,7 +4912,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
results.numInteresting++;
- if (isDrawnLw()) {
+ if (isDrawn()) {
results.numDrawn++;
if (!isAnimating(TRANSITION | PARENTS)) {
results.numVisible++;
@@ -5033,7 +5048,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
int relayoutVisibleWindow(int result, int attrChanges) {
final boolean wasVisible = isVisibleLw();
- result |= (!wasVisible || !isDrawnLw()) ? RELAYOUT_RES_FIRST_TIME : 0;
+ result |= (!wasVisible || !isDrawn()) ? RELAYOUT_RES_FIRST_TIME : 0;
if (mAnimatingExit) {
Slog.d(TAG, "relayoutVisibleWindow: " + this + " mAnimatingExit=true, mRemoveOnExit="
@@ -5605,15 +5620,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return !mTapExcludeRegion.isEmpty();
}
- @Override
- public boolean isInputMethodTarget() {
+ boolean isInputMethodTarget() {
return getDisplayContent().mInputMethodTarget == this;
}
long getFrameNumber() {
// Return the frame number in which changes requested in this layout will be rendered or
// -1 if we do not expect the frame to be rendered.
- return getFrameLw().isEmpty() ? -1 : mFrameNumber;
+ return getFrame().isEmpty() ? -1 : mFrameNumber;
}
void setFrameNumber(long frameNumber) {
@@ -5676,8 +5690,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mWindowFrames.mVisibleInsets;
}
- @Override
- public WindowFrames getWindowFrames() {
+ /** Returns the {@link WindowFrames} associated with this {@link WindowState}. */
+ WindowFrames getWindowFrames() {
return mWindowFrames;
}
@@ -5785,7 +5799,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// won't exactly match the final freeform window frame (e.g. when overlapping with
// the status bar). In that case we need to use the final frame.
if (inFreeformWindowingMode()) {
- outFrame.set(getFrameLw());
+ outFrame.set(getFrame());
} else if (isLetterboxedAppWindow() || mToken.isFixedRotationTransforming()) {
// 1. The letterbox surfaces should be animated with the owner activity, so use task
// bounds to include them.
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 92177abbbf85..1bd712c3638b 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -38,6 +38,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
@@ -525,13 +526,13 @@ class WindowStateAnimator {
if (DEBUG) {
Slog.v(TAG, "Got surface: " + mSurfaceController
- + ", set left=" + w.getFrameLw().left + " top=" + w.getFrameLw().top);
+ + ", set left=" + w.getFrame().left + " top=" + w.getFrame().top);
}
if (SHOW_LIGHT_TRANSACTIONS) {
Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked");
WindowManagerService.logSurface(w, "CREATE pos=("
- + w.getFrameLw().left + "," + w.getFrameLw().top + ") ("
+ + w.getFrame().left + "," + w.getFrame().top + ") ("
+ width + "x" + height + ")" + " HIDE", false);
}
@@ -659,80 +660,7 @@ class WindowStateAnimator {
}
void computeShownFrameLocked() {
- final ScreenRotationAnimation screenRotationAnimation =
- mWin.getDisplayContent().getRotationAnimation();
- final boolean windowParticipatesInScreenRotationAnimation =
- !mWin.mForceSeamlesslyRotate;
- final boolean screenAnimation = screenRotationAnimation != null
- && screenRotationAnimation.isAnimating()
- && windowParticipatesInScreenRotationAnimation;
-
- if (screenAnimation) {
- // cache often used attributes locally
- final Rect frame = mWin.getFrameLw();
- final float tmpFloats[] = mService.mTmpFloats;
- final Matrix tmpMatrix = mWin.mTmpMatrix;
-
- // Compute the desired transformation.
- if (screenRotationAnimation.isRotating()) {
- // If we are doing a screen animation, the global rotation
- // applied to windows can result in windows that are carefully
- // aligned with each other to slightly separate, allowing you
- // to see what is behind them. An unsightly mess. This...
- // thing... magically makes it call good: scale each window
- // slightly (two pixels larger in each dimension, from the
- // window's center).
- final float w = frame.width();
- final float h = frame.height();
- if (w>=1 && h>=1) {
- tmpMatrix.setScale(1 + 2/w, 1 + 2/h, w/2, h/2);
- } else {
- tmpMatrix.reset();
- }
- } else {
- tmpMatrix.reset();
- }
-
- tmpMatrix.postScale(mWin.mGlobalScale, mWin.mGlobalScale);
-
- // WindowState.prepareSurfaces expands for surface insets (in order they don't get
- // clipped by the WindowState surface), so we need to go into the other direction here.
- tmpMatrix.postTranslate(mWin.mAttrs.surfaceInsets.left,
- mWin.mAttrs.surfaceInsets.top);
-
-
- // "convert" it into SurfaceFlinger's format
- // (a 2x2 matrix + an offset)
- // Here we must not transform the position of the surface
- // since it is already included in the transformation.
- //Slog.i(TAG_WM, "Transform: " + matrix);
-
- mHaveMatrix = true;
- tmpMatrix.getValues(tmpFloats);
- mDsDx = tmpFloats[Matrix.MSCALE_X];
- mDtDx = tmpFloats[Matrix.MSKEW_Y];
- mDtDy = tmpFloats[Matrix.MSKEW_X];
- mDsDy = tmpFloats[Matrix.MSCALE_Y];
-
- // Now set the alpha... but because our current hardware
- // can't do alpha transformation on a non-opaque surface,
- // turn it off if we are running an animation that is also
- // transforming since it is more important to have that
- // animation be smooth.
- mShownAlpha = mAlpha;
- if (!mService.mLimitedAlphaCompositing
- || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
- || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)))) {
- mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha();
- }
-
- if ((DEBUG_ANIM || DEBUG) && (mShownAlpha == 1.0 || mShownAlpha == 0.0)) {
- Slog.v(TAG, "computeShownFrameLocked: Animating " + this + " mAlpha=" + mAlpha
- + " screen=" + (screenAnimation
- ? screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));
- }
- return;
- } else if (mIsWallpaper && mService.mRoot.mWallpaperActionPending) {
+ if (mIsWallpaper && mService.mRoot.mWallpaperActionPending) {
return;
} else if (mWin.isDragResizeChanged()) {
// This window is awaiting a relayout because user just started (or ended)
@@ -968,7 +896,7 @@ class WindowStateAnimator {
// There is no need to wait for an animation change if our window is gone for layout
// already as we'll never be visible.
- if (w.getOrientationChanging() && w.isGoneForLayoutLw()) {
+ if (w.getOrientationChanging() && w.isGoneForLayout()) {
ProtoLog.v(WM_DEBUG_ORIENTATION, "Orientation change skips hidden %s", w);
w.setOrientationChanging(false);
}
@@ -992,7 +920,7 @@ class WindowStateAnimator {
// really hidden (gone for layout), there is no point in still waiting for it.
// Note that this does introduce a potential glitch if the window becomes unhidden
// before it has drawn for the new orientation.
- if (w.getOrientationChanging() && w.isGoneForLayoutLw()) {
+ if (w.getOrientationChanging() && w.isGoneForLayout()) {
w.setOrientationChanging(false);
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Orientation change skips hidden %s", w);
@@ -1070,7 +998,7 @@ class WindowStateAnimator {
}
if (w.getOrientationChanging()) {
- if (!w.isDrawnLw()) {
+ if (!w.isDrawn()) {
mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;
mAnimator.mLastWindowFreezeSource = w;
ProtoLog.v(WM_DEBUG_ORIENTATION,
@@ -1327,7 +1255,7 @@ class WindowStateAnimator {
mWin.getDisplayContent().adjustForImeIfNeeded();
}
- return mWin.isAnimating(PARENTS);
+ return mWin.isAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION);
}
void dumpDebug(ProtoOutputStream proto, long fieldId) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6154bef2bda3..22e309cdc2b4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -302,7 +302,6 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
@@ -322,7 +321,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -575,13 +573,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private final CertificateMonitor mCertificateMonitor;
private final SecurityLogMonitor mSecurityLogMonitor;
+ private final RemoteBugreportManager mBugreportCollectionManager;
@GuardedBy("getLockObject()")
private NetworkLogger mNetworkLogger;
- private final AtomicBoolean mRemoteBugreportServiceIsActive = new AtomicBoolean();
- private final AtomicBoolean mRemoteBugreportSharingAccepted = new AtomicBoolean();
-
private final SetupContentObserver mSetupContentObserver;
private final DevicePolicyConstantsObserver mConstantsObserver;
@@ -633,44 +629,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@VisibleForTesting
final TransferOwnershipMetadataManager mTransferOwnershipMetadataManager;
- private final Runnable mRemoteBugreportTimeoutRunnable = new Runnable() {
- @Override
- public void run() {
- if(mRemoteBugreportServiceIsActive.get()) {
- onBugreportFailed();
- }
- }
- };
-
- /** Listens only if mHasFeature == true. */
- private final BroadcastReceiver mRemoteBugreportFinishedReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH.equals(intent.getAction())
- && mRemoteBugreportServiceIsActive.get()) {
- onBugreportFinished(intent);
- }
- }
- };
-
- /** Listens only if mHasFeature == true. */
- private final BroadcastReceiver mRemoteBugreportConsentReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- mInjector.getNotificationManager().cancel(LOG_TAG,
- RemoteBugreportUtils.NOTIFICATION_ID);
- if (DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
- onBugreportSharingAccepted();
- } else if (DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED.equals(action)) {
- onBugreportSharingDeclined();
- }
- mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
- }
- };
-
public static final class Lifecycle extends SystemService {
private BaseIDevicePolicyManager mService;
@@ -748,17 +706,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
- && userHandle == mOwners.getDeviceOwnerUserId()
- && getDeviceOwnerRemoteBugreportUri() != null) {
- IntentFilter filterConsent = new IntentFilter();
- filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED);
- filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED);
- mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG,
- RemoteBugreportUtils.NOTIFICATION_ID,
- RemoteBugreportUtils.buildNotification(mContext,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
- UserHandle.ALL);
+ && userHandle == mOwners.getDeviceOwnerUserId()) {
+ mBugreportCollectionManager.checkForPendingBugreportAfterBoot();
+
}
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
@@ -1435,10 +1385,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mCertificateMonitor = new CertificateMonitor(this, mInjector, mBackgroundHandler);
mDeviceAdminServiceController = new DeviceAdminServiceController(this, mConstants);
-
mOverlayPackagesProvider = new OverlayPackagesProvider(mContext);
-
mTransferOwnershipMetadataManager = mInjector.newTransferOwnershipMetadataManager();
+ mBugreportCollectionManager = new RemoteBugreportManager(this, mInjector);
if (!mHasFeature) {
// Skip the rest of the initialization
@@ -1566,7 +1515,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
/**
* Creates a new {@link CallerIdentity} object to represent the caller's identity.
*/
- private CallerIdentity getCallerIdentity(String callerPackage) {
+ private CallerIdentity getCallerIdentity() {
+ final int callerUid = mInjector.binderGetCallingUid();
+ return new CallerIdentity(callerUid, null, null);
+ }
+
+ /**
+ * Creates a new {@link CallerIdentity} object to represent the caller's identity.
+ */
+ private CallerIdentity getCallerIdentity(@NonNull String callerPackage) {
final int callerUid = mInjector.binderGetCallingUid();
if (!isCallingFromPackage(callerPackage, callerUid)) {
@@ -2127,6 +2084,81 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
reqPolicy, /* permission= */ null);
}
+ @NonNull ActiveAdmin getDeviceOwnerOfCallerLocked(final CallerIdentity caller) {
+ ensureLocked();
+ ComponentName doComponent = mOwners.getDeviceOwnerComponent();
+ Preconditions.checkState(doComponent != null,
+ String.format("No device owner for user %d", caller.getUid()));
+
+ // Use the user ID of the caller instead of mOwners.getDeviceOwnerUserId() because
+ // secondary, affiliated users will have their own admin.
+ ActiveAdmin doAdmin = getUserData(caller.getUserId()).mAdminMap.get(doComponent);
+ Preconditions.checkState(doAdmin != null,
+ String.format("Device owner %s for user %d not found", doComponent,
+ caller.getUid()));
+
+ Preconditions.checkSecurity(doAdmin.getUid() == caller.getUid(),
+ String.format("Admin %s is not owned by uid %d, but uid %d", doComponent,
+ caller.getUid(), doAdmin.getUid()));
+
+ Preconditions.checkSecurity(doAdmin.info.getComponent().equals(caller.getComponentName()),
+ String.format("Caller component %s is not device owner",
+ caller.getComponentName()));
+
+ return doAdmin;
+ }
+
+ @NonNull ActiveAdmin getProfileOwnerOfCallerLocked(final CallerIdentity caller) {
+ ensureLocked();
+ final ComponentName poAdminComponent = mOwners.getProfileOwnerComponent(caller.getUserId());
+
+ Preconditions.checkState(poAdminComponent != null,
+ String.format("No profile owner for user %d", caller.getUid()));
+
+ ActiveAdmin poAdmin = getUserData(caller.getUserId()).mAdminMap.get(poAdminComponent);
+ Preconditions.checkState(poAdmin != null,
+ String.format("No device profile owner for caller %d", caller.getUid()));
+
+ Preconditions.checkSecurity(poAdmin.getUid() == caller.getUid(),
+ String.format("Admin %s is not owned by uid %d", poAdminComponent,
+ caller.getUid()));
+
+ Preconditions.checkSecurity(poAdmin.info.getComponent().equals(caller.getComponentName()),
+ String.format("Caller component %s is not profile owner",
+ caller.getComponentName()));
+
+ return poAdmin;
+ }
+
+ @NonNull ActiveAdmin getOrganizationOwnedProfileOwnerLocked(final CallerIdentity caller) {
+ final ActiveAdmin profileOwner = getProfileOwnerOfCallerLocked(caller);
+
+ Preconditions.checkSecurity(
+ mOwners.isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId()),
+ String.format("Admin %s is not of an org-owned device",
+ profileOwner.info.getComponent()));
+
+ return profileOwner;
+ }
+
+ @NonNull ActiveAdmin getProfileOwnerOrDeviceOwnerLocked(final CallerIdentity caller) {
+ ensureLocked();
+ // Try to find an admin which can use reqPolicy
+ final ComponentName poAdminComponent = mOwners.getProfileOwnerComponent(caller.getUserId());
+ final ComponentName doAdminComponent = mOwners.getDeviceOwnerComponent();
+
+ if (poAdminComponent == null && doAdminComponent == null) {
+ throw new IllegalStateException(
+ String.format("No profile or device owner for user %d", caller.getUid()));
+ }
+
+ if (poAdminComponent != null) {
+ return getProfileOwnerOfCallerLocked(caller);
+ }
+
+ return getDeviceOwnerOfCallerLocked(caller);
+ }
+
/**
* Finds an active admin for the caller then checks {@code permission} if admin check failed.
*
@@ -2145,9 +2177,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
ActiveAdmin result = getActiveAdminWithPolicyForUidLocked(who, reqPolicy, callingUid);
if (result != null) {
return result;
- } else if (permission != null
- && (mContext.checkCallingPermission(permission)
- == PackageManager.PERMISSION_GRANTED)) {
+ } else if (permission != null && hasCallingPermission(permission)) {
return null;
}
@@ -2844,9 +2874,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle,
Bundle onEnableData) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
DevicePolicyData policy = getUserData(userHandle);
DeviceAdminInfo info = findAdmin(adminReceiver, userHandle,
@@ -2986,7 +3019,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return false;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
}
@@ -2997,7 +3034,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return false;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
DevicePolicyData policyData = getUserData(userHandle);
return policyData.mRemovingAdmins.contains(adminReceiver);
@@ -3009,7 +3050,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return false;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity(adminReceiver);
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (administrator == null) {
@@ -3025,8 +3070,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return Collections.EMPTY_LIST;
}
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
- enforceFullCrossUsersPermission(userHandle);
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
@@ -3046,7 +3094,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return false;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
@@ -3156,8 +3208,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
enforceUserUnlocked(userHandle);
+
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (admin == null) {
@@ -3309,7 +3365,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return PASSWORD_QUALITY_UNSPECIFIED;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
int mode = PASSWORD_QUALITY_UNSPECIFIED;
@@ -3521,7 +3581,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return 0L;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
long timeout = 0L;
@@ -3547,12 +3611,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean addCrossProfileWidgetProvider(ComponentName admin, String packageName) {
- final int userId = UserHandle.getCallingUserId();
+ final CallerIdentity identity = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
List<String> changedProviders = null;
synchronized (getLockObject()) {
- ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(admin,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (activeAdmin.crossProfileWidgetProviders == null) {
activeAdmin.crossProfileWidgetProviders = new ArrayList<>();
}
@@ -3560,7 +3624,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!providers.contains(packageName)) {
providers.add(packageName);
changedProviders = new ArrayList<>(providers);
- saveSettingsLocked(userId);
+ saveSettingsLocked(identity.getUserId());
}
}
@@ -3570,7 +3634,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
.write();
if (changedProviders != null) {
- mLocalService.notifyCrossProfileProvidersChanged(userId, changedProviders);
+ mLocalService.notifyCrossProfileProvidersChanged(identity.getUserId(),
+ changedProviders);
return true;
}
@@ -3579,12 +3644,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean removeCrossProfileWidgetProvider(ComponentName admin, String packageName) {
- final int userId = UserHandle.getCallingUserId();
+ final CallerIdentity identity = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
List<String> changedProviders = null;
synchronized (getLockObject()) {
- ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(admin,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (activeAdmin.crossProfileWidgetProviders == null
|| activeAdmin.crossProfileWidgetProviders.isEmpty()) {
return false;
@@ -3592,7 +3657,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
List<String> providers = activeAdmin.crossProfileWidgetProviders;
if (providers.remove(packageName)) {
changedProviders = new ArrayList<>(providers);
- saveSettingsLocked(userId);
+ saveSettingsLocked(identity.getUserId());
}
}
@@ -3602,7 +3667,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
.write();
if (changedProviders != null) {
- mLocalService.notifyCrossProfileProvidersChanged(userId, changedProviders);
+ mLocalService.notifyCrossProfileProvidersChanged(identity.getUserId(),
+ changedProviders);
return true;
}
@@ -3611,9 +3677,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public List<String> getCrossProfileWidgetProviders(ComponentName admin) {
+ final CallerIdentity identity = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+
synchronized (getLockObject()) {
- ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(admin,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (activeAdmin.crossProfileWidgetProviders == null
|| activeAdmin.crossProfileWidgetProviders.isEmpty()) {
return null;
@@ -3656,7 +3724,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return 0L;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
return getPasswordExpirationLocked(who, userHandle, parent);
}
@@ -3862,7 +3934,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return 0;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
if (who != null) {
final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
@@ -3902,7 +3978,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
new PasswordMetrics(CREDENTIAL_TYPE_NONE);
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
ArrayList<PasswordMetrics> adminMetrics = new ArrayList<>();
synchronized (getLockObject()) {
List<ActiveAdmin> admins =
@@ -3919,7 +3999,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return true;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
enforceUserUnlocked(userHandle, parent);
synchronized (getLockObject()) {
@@ -3951,7 +4034,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return true;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
enforceManagedProfile(userHandle, "call APIs refering to the parent profile");
synchronized (getLockObject()) {
@@ -3970,7 +4056,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return true;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
enforceNotManagedProfile(userHandle, "check password sufficiency");
enforceUserUnlocked(userHandle);
@@ -4058,12 +4147,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mLockPatternUtils.hasSecureLockScreen()) {
return 0;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
- if (!isCallerWithSystemUid()) {
+ if (!isSystemUid(identity)) {
// This API can be called by an active device admin or by keyguard code.
- if (mContext.checkCallingPermission(permission.ACCESS_KEYGUARD_SECURE_STORAGE)
- != PackageManager.PERMISSION_GRANTED) {
+ if (!hasCallingPermission(permission.ACCESS_KEYGUARD_SECURE_STORAGE)) {
getActiveAdminForCallerLocked(
null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
}
@@ -4106,7 +4198,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return 0;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
ActiveAdmin admin = (who != null)
? getActiveAdminUncheckedLocked(who, userHandle, parent)
@@ -4120,7 +4216,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return UserHandle.USER_NULL;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
ActiveAdmin admin = getAdminWithMinimumFailedPasswordsForWipeLocked(
userHandle, parent);
@@ -4191,8 +4291,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// As of R, only privlleged caller holding RESET_PASSWORD can call resetPassword() to
// set password to an unsecured user.
- if (mContext.checkCallingPermission(permission.RESET_PASSWORD)
- == PackageManager.PERMISSION_GRANTED) {
+ if (hasCallingPermission(permission.RESET_PASSWORD)) {
return setPasswordPrivileged(password, flags, callingUid);
}
@@ -4392,7 +4491,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return 0;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
if (who != null) {
final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
@@ -4465,12 +4568,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
}
+ Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userId));
+
if (!mLockPatternUtils.hasSecureLockScreen()) {
// No strong auth timeout on devices not supporting the
// {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature
return 0;
}
- enforceFullCrossUsersPermission(userId);
synchronized (getLockObject()) {
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userId, parent);
@@ -4504,8 +4611,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void lockNow(int flags, boolean parent) {
- if (!mHasFeature && mContext.checkCallingPermission(android.Manifest.permission.LOCK_DEVICE)
- != PackageManager.PERMISSION_GRANTED) {
+ if (!mHasFeature && !hasCallingPermission(permission.LOCK_DEVICE)) {
return;
}
@@ -4597,8 +4703,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
private void enforceNetworkStackOrProfileOrDeviceOwner(ComponentName who) {
- if (mContext.checkCallingPermission(PERMISSION_MAINLINE_NETWORK_STACK)
- == PackageManager.PERMISSION_GRANTED) {
+ if (hasCallingPermission(PERMISSION_MAINLINE_NETWORK_STACK)) {
return;
}
enforceProfileOrDeviceOwner(who);
@@ -5677,8 +5782,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return;
}
-
- enforceFullCrossUsersPermission(mInjector.userHandleGetCallingUserId());
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(isSystemUid(identity) || isRootUid(identity)
+ || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL));
final ActiveAdmin admin;
synchronized (getLockObject()) {
@@ -5854,8 +5960,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
synchronized (getLockObject()) {
if (who == null) {
if ((frpManagementAgentUid != mInjector.binderGetCallingUid())
- && (mContext.checkCallingPermission(permission.MASTER_CLEAR)
- != PackageManager.PERMISSION_GRANTED)) {
+ && !hasCallingPermission(permission.MASTER_CLEAR)) {
throw new SecurityException(
"Must be called by the FRP management agent on device");
}
@@ -5893,9 +5998,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return;
}
- enforceFullCrossUsersPermission(userHandle);
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = comp != null
+ ? getCallerIdentity(comp)
+ : getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(comp, userHandle);
@@ -5972,13 +6081,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void reportFailedPasswordAttempt(int userHandle) {
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
if (!isSeparateProfileChallengeEnabled(userHandle)) {
enforceNotManagedProfile(userHandle,
"report failed password attempt if separate profile challenge is not in place");
}
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.BIND_DEVICE_ADMIN, null);
boolean wipeData = false;
ActiveAdmin strictestAdmin = null;
@@ -6051,9 +6162,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void reportSuccessfulPasswordAttempt(int userHandle) {
- enforceFullCrossUsersPermission(userHandle);
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(userHandle);
@@ -6079,9 +6192,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void reportFailedBiometricAttempt(int userHandle) {
- enforceFullCrossUsersPermission(userHandle);
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
+
if (mInjector.securityLogIsLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 0,
/*method strength*/ 0);
@@ -6090,9 +6206,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void reportSuccessfulBiometricAttempt(int userHandle) {
- enforceFullCrossUsersPermission(userHandle);
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
+
if (mInjector.securityLogIsLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 1,
/*method strength*/ 0);
@@ -6101,9 +6220,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void reportKeyguardDismissed(int userHandle) {
- enforceFullCrossUsersPermission(userHandle);
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
if (mInjector.securityLogIsLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISSED);
@@ -6112,9 +6233,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void reportKeyguardSecured(int userHandle) {
- enforceFullCrossUsersPermission(userHandle);
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
if (mInjector.securityLogIsLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_SECURED);
@@ -6176,7 +6299,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return null;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
// Scan through active admins and find if anyone has already
@@ -6310,7 +6437,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return false;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = who != null
+ ? getCallerIdentity(who)
+ : getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
// Check for permissions if a particular caller is specified
if (who != null) {
@@ -6340,7 +6473,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
// Ok to return current status.
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = callerPackage != null
+ ? getCallerIdentity(callerPackage)
+ : getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
// It's not critical here, but let's make sure the package name is correct, in case
// we start using it for different purposes.
@@ -6485,24 +6623,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final int userHandle = UserHandle.getCallingUserId();
+ final CallerIdentity identity = getCallerIdentity(who);
+
boolean requireAutoTimeChanged = false;
synchronized (getLockObject()) {
- if (isManagedProfile(userHandle)) {
- throw new SecurityException("Managed profile cannot set auto time required");
- }
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ Preconditions.checkSecurity(!isManagedProfile(identity.getUserId()),
+ "Managed profile cannot set auto time required");
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (admin.requireAutoTime != required) {
admin.requireAutoTime = required;
- saveSettingsLocked(userHandle);
+ saveSettingsLocked(identity.getUserId());
requireAutoTimeChanged = true;
}
}
// requireAutoTime is now backed by DISALLOW_CONFIG_DATE_TIME restriction, so propagate
// updated restrictions to the framework.
if (requireAutoTimeChanged) {
- pushUserRestrictions(userHandle);
+ pushUserRestrictions(identity.getUserId());
}
// Turn AUTO_TIME on in settings if it is required
if (required) {
@@ -6679,45 +6816,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkCallAuthorization(isDeviceOwner(identity));
ensureAllUsersAffiliated();
- if (mRemoteBugreportServiceIsActive.get()
- || (getDeviceOwnerRemoteBugreportUri() != null)) {
- Slog.d(LOG_TAG, "Remote bugreport wasn't started because there's already one running.");
- return false;
- }
-
- final long currentTime = System.currentTimeMillis();
- synchronized (getLockObject()) {
- DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM);
- if (currentTime > policyData.mLastBugReportRequestTime) {
- policyData.mLastBugReportRequestTime = currentTime;
- saveSettingsLocked(UserHandle.USER_SYSTEM);
- }
- }
-
- final long callingIdentity = mInjector.binderClearCallingIdentity();
- try {
- mInjector.getIActivityManager().requestRemoteBugReport();
-
- mRemoteBugreportServiceIsActive.set(true);
- mRemoteBugreportSharingAccepted.set(false);
- registerRemoteBugreportReceivers();
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG,
- RemoteBugreportUtils.NOTIFICATION_ID,
- RemoteBugreportUtils.buildNotification(mContext,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED), UserHandle.ALL);
- mHandler.postDelayed(mRemoteBugreportTimeoutRunnable,
- RemoteBugreportUtils.REMOTE_BUGREPORT_TIMEOUT_MILLIS);
+ if (mBugreportCollectionManager.requestBugreport()) {
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.REQUEST_BUGREPORT)
.setAdmin(who)
.write();
+
+ final long currentTime = System.currentTimeMillis();
+ synchronized (getLockObject()) {
+ DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM);
+ if (currentTime > policyData.mLastBugReportRequestTime) {
+ policyData.mLastBugReportRequestTime = currentTime;
+ saveSettingsLocked(UserHandle.USER_SYSTEM);
+ }
+ }
+
return true;
- } catch (RemoteException re) {
- // should never happen
- Slog.e(LOG_TAG, "Failed to make remote calls to start bugreportremote service", re);
+ } else {
return false;
- } finally {
- mInjector.binderRestoreCallingIdentity(callingIdentity);
}
}
@@ -6761,146 +6877,36 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
}
- private String getDeviceOwnerRemoteBugreportUri() {
+ void sendBugreportToDeviceOwner(Uri bugreportUri, String bugreportHash) {
synchronized (getLockObject()) {
- return mOwners.getDeviceOwnerRemoteBugreportUri();
+ final Intent intent = new Intent(DeviceAdminReceiver.ACTION_BUGREPORT_SHARE);
+ intent.setComponent(mOwners.getDeviceOwnerComponent());
+ intent.setDataAndType(bugreportUri, RemoteBugreportManager.BUGREPORT_MIMETYPE);
+ intent.putExtra(DeviceAdminReceiver.EXTRA_BUGREPORT_HASH, bugreportHash);
+ intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ final UriGrantsManagerInternal ugm = LocalServices
+ .getService(UriGrantsManagerInternal.class);
+ final NeededUriGrants needed = ugm.checkGrantUriPermissionFromIntent(intent,
+ Process.SHELL_UID, mOwners.getDeviceOwnerComponent().getPackageName(),
+ mOwners.getDeviceOwnerUserId());
+ ugm.grantUriPermissionUncheckedFromIntent(needed, null);
+
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(mOwners.getDeviceOwnerUserId()));
}
}
- private void setDeviceOwnerRemoteBugreportUriAndHash(String bugreportUri,
- String bugreportHash) {
+ void setDeviceOwnerRemoteBugreportUriAndHash(String bugreportUri, String bugreportHash) {
synchronized (getLockObject()) {
mOwners.setDeviceOwnerRemoteBugreportUriAndHash(bugreportUri, bugreportHash);
}
}
- private void registerRemoteBugreportReceivers() {
- try {
- IntentFilter filterFinished = new IntentFilter(
- DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH,
- RemoteBugreportUtils.BUGREPORT_MIMETYPE);
- mContext.registerReceiver(mRemoteBugreportFinishedReceiver, filterFinished);
- } catch (IntentFilter.MalformedMimeTypeException e) {
- // should never happen, as setting a constant
- Slog.w(LOG_TAG, "Failed to set type " + RemoteBugreportUtils.BUGREPORT_MIMETYPE, e);
- }
- IntentFilter filterConsent = new IntentFilter();
- filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED);
- filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED);
- mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
- }
-
- private void onBugreportFinished(Intent intent) {
- mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
- mRemoteBugreportServiceIsActive.set(false);
- Uri bugreportUri = intent.getData();
- String bugreportUriString = null;
- if (bugreportUri != null) {
- bugreportUriString = bugreportUri.toString();
- }
- String bugreportHash = intent.getStringExtra(
- DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH);
- if (mRemoteBugreportSharingAccepted.get()) {
- shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
- mInjector.getNotificationManager().cancel(LOG_TAG,
- RemoteBugreportUtils.NOTIFICATION_ID);
- } else {
- setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash);
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
- RemoteBugreportUtils.buildNotification(mContext,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
- UserHandle.ALL);
- }
- mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
- }
-
- private void onBugreportFailed() {
- mRemoteBugreportServiceIsActive.set(false);
- mInjector.systemPropertiesSet(RemoteBugreportUtils.CTL_STOP,
- RemoteBugreportUtils.REMOTE_BUGREPORT_SERVICE);
- mRemoteBugreportSharingAccepted.set(false);
- setDeviceOwnerRemoteBugreportUriAndHash(null, null);
- mInjector.getNotificationManager().cancel(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID);
- Bundle extras = new Bundle();
- extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
- DeviceAdminReceiver.BUGREPORT_FAILURE_FAILED_COMPLETING);
- sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_FAILED, extras);
- mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
- mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
- }
-
- private void onBugreportSharingAccepted() {
- mRemoteBugreportSharingAccepted.set(true);
- String bugreportUriString = null;
- String bugreportHash = null;
+ Pair<String, String> getDeviceOwnerRemoteBugreportUriAndHash() {
synchronized (getLockObject()) {
- bugreportUriString = getDeviceOwnerRemoteBugreportUri();
- bugreportHash = mOwners.getDeviceOwnerRemoteBugreportHash();
- }
- if (bugreportUriString != null) {
- shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
- } else if (mRemoteBugreportServiceIsActive.get()) {
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
- RemoteBugreportUtils.buildNotification(mContext,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED),
- UserHandle.ALL);
- }
- }
-
- private void onBugreportSharingDeclined() {
- if (mRemoteBugreportServiceIsActive.get()) {
- mInjector.systemPropertiesSet(RemoteBugreportUtils.CTL_STOP,
- RemoteBugreportUtils.REMOTE_BUGREPORT_SERVICE);
- mRemoteBugreportServiceIsActive.set(false);
- mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
- mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
- }
- mRemoteBugreportSharingAccepted.set(false);
- setDeviceOwnerRemoteBugreportUriAndHash(null, null);
- sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_SHARING_DECLINED, null);
- }
-
- private void shareBugreportWithDeviceOwnerIfExists(String bugreportUriString,
- String bugreportHash) {
- ParcelFileDescriptor pfd = null;
- try {
- if (bugreportUriString == null) {
- throw new FileNotFoundException();
- }
- Uri bugreportUri = Uri.parse(bugreportUriString);
- pfd = mContext.getContentResolver().openFileDescriptor(bugreportUri, "r");
-
- synchronized (getLockObject()) {
- Intent intent = new Intent(DeviceAdminReceiver.ACTION_BUGREPORT_SHARE);
- intent.setComponent(mOwners.getDeviceOwnerComponent());
- intent.setDataAndType(bugreportUri, RemoteBugreportUtils.BUGREPORT_MIMETYPE);
- intent.putExtra(DeviceAdminReceiver.EXTRA_BUGREPORT_HASH, bugreportHash);
- intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
- final UriGrantsManagerInternal ugm = LocalServices
- .getService(UriGrantsManagerInternal.class);
- final NeededUriGrants needed = ugm.checkGrantUriPermissionFromIntent(intent,
- Process.SHELL_UID, mOwners.getDeviceOwnerComponent().getPackageName(),
- mOwners.getDeviceOwnerUserId());
- ugm.grantUriPermissionUncheckedFromIntent(needed, null);
-
- mContext.sendBroadcastAsUser(intent, UserHandle.of(mOwners.getDeviceOwnerUserId()));
- }
- } catch (FileNotFoundException e) {
- Bundle extras = new Bundle();
- extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
- DeviceAdminReceiver.BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE);
- sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_FAILED, extras);
- } finally {
- try {
- if (pfd != null) {
- pfd.close();
- }
- } catch (IOException ex) {
- // Ignore
- }
- mRemoteBugreportSharingAccepted.set(false);
- setDeviceOwnerRemoteBugreportUriAndHash(null, null);
+ final String uri = mOwners.getDeviceOwnerRemoteBugreportUri();
+ return uri == null ? null
+ : new Pair<>(uri, mOwners.getDeviceOwnerRemoteBugreportHash());
}
}
@@ -7033,7 +7039,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return 0;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
final long ident = mInjector.binderClearCallingIdentity();
try {
synchronized (getLockObject()) {
@@ -7229,6 +7239,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return who != null && who.equals(profileOwner);
}
+ /**
+ * Returns {@code true} if the provided caller identity is of a profile owner.
+ * @param identity identity of caller.
+ * @return true if {@code identity} is a profile owner, false otherwise.
+ */
+ public boolean isProfileOwner(CallerIdentity identity) {
+ final ComponentName profileOwner = getProfileOwner(identity.getUserId());
+ return profileOwner != null && profileOwner.equals(identity.getComponentName());
+ }
+
private boolean hasProfileOwner(int userId) {
synchronized (getLockObject()) {
return mOwners.hasProfileOwner(userId);
@@ -7783,7 +7803,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public ComponentName getProfileOwnerAsUser(int userHandle) {
- enforceCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasCrossUsersPermission(identity, userHandle));
return getProfileOwner(userHandle);
}
@@ -8140,56 +8163,31 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
- private void enforceAcrossUsersPermissions() {
- final int callingUid = mInjector.binderGetCallingUid();
- final int callingPid = mInjector.binderGetCallingPid();
- final String packageName = mContext.getPackageName();
-
- if (isCallerWithSystemUid() || callingUid == Process.ROOT_UID) {
- return;
- }
- if (PermissionChecker.checkPermissionForPreflight(
- mContext, permission.INTERACT_ACROSS_PROFILES, callingPid, callingUid,
- packageName) == PermissionChecker.PERMISSION_GRANTED) {
- return;
- }
- if (mContext.checkCallingPermission(permission.INTERACT_ACROSS_USERS)
- == PackageManager.PERMISSION_GRANTED) {
- return;
- }
- if (mContext.checkCallingPermission(permission.INTERACT_ACROSS_USERS_FULL)
- == PackageManager.PERMISSION_GRANTED) {
- return;
- }
- throw new SecurityException("Calling user does not have INTERACT_ACROSS_PROFILES or"
- + "INTERACT_ACROSS_USERS or INTERACT_ACROSS_USERS_FULL permissions");
+ private boolean hasCallingPermission(String permission) {
+ return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
}
- private void enforceFullCrossUsersPermission(int userHandle) {
- enforceSystemUserOrPermissionIfCrossUser(userHandle,
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ private boolean hasCallingOrSelfPermission(String permission) {
+ return mContext.checkCallingOrSelfPermission(permission)
+ == PackageManager.PERMISSION_GRANTED;
}
- private void enforceCrossUsersPermission(int userHandle) {
- enforceSystemUserOrPermissionIfCrossUser(userHandle,
- android.Manifest.permission.INTERACT_ACROSS_USERS);
+ private boolean hasPermissionForPreflight(CallerIdentity identity, String permission) {
+ final int callingPid = mInjector.binderGetCallingPid();
+ final String packageName = mContext.getPackageName();
+
+ return PermissionChecker.checkPermissionForPreflight(mContext, permission, callingPid,
+ identity.getUid(), packageName) == PermissionChecker.PERMISSION_GRANTED;
}
- private void enforceSystemUserOrPermission(String permission) {
- if (!(isCallerWithSystemUid() || mInjector.binderGetCallingUid() == Process.ROOT_UID)) {
- mContext.enforceCallingOrSelfPermission(permission,
- "Must be system or have " + permission + " permission");
- }
+ private boolean hasFullCrossUsersPermission(CallerIdentity identity, int userHandle) {
+ return (userHandle == identity.getUserId()) || isSystemUid(identity) || isRootUid(identity)
+ || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL);
}
- private void enforceSystemUserOrPermissionIfCrossUser(int userHandle, String permission) {
- if (userHandle < 0) {
- throw new IllegalArgumentException("Invalid userId " + userHandle);
- }
- if (userHandle == mInjector.userHandleGetCallingUserId()) {
- return;
- }
- enforceSystemUserOrPermission(permission);
+ private boolean hasCrossUsersPermission(CallerIdentity identity, int userHandle) {
+ return (userHandle == identity.getUserId()) || isSystemUid(identity) || isRootUid(identity)
+ || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS);
}
private void enforceManagedProfile(int userId, String message) {
@@ -8249,19 +8247,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
throw new SecurityException("No active admin found");
}
- private void enforceProfileOwnerOrFullCrossUsersPermission(int userId) {
- if (userId == mInjector.userHandleGetCallingUserId()) {
+ private void enforceProfileOwnerOrFullCrossUsersPermission(CallerIdentity identity,
+ int userId) {
+ if (userId == identity.getUserId()) {
synchronized (getLockObject()) {
if (getActiveAdminWithPolicyForUidLocked(null,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, mInjector.binderGetCallingUid())
- != null) {
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, identity.getUid()) != null) {
// Device Owner/Profile Owner may access the user it runs on.
return;
}
}
}
- // Otherwise, INTERACT_ACROSS_USERS_FULL permission, system UID or root UID is required.
- enforceSystemUserOrPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userId));
}
private boolean canUserUseLockTaskLocked(int userId) {
@@ -8315,6 +8312,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID);
}
+ private boolean isSystemUid(CallerIdentity identity) {
+ return UserHandle.isSameApp(identity.getUid(), Process.SYSTEM_UID);
+ }
+
+ private boolean isRootUid(CallerIdentity identity) {
+ return UserHandle.isSameApp(identity.getUid(), Process.ROOT_UID);
+ }
+
+ private boolean isShellUid(CallerIdentity identity) {
+ return UserHandle.isSameApp(identity.getUid(), Process.SHELL_UID);
+ }
+
protected int getProfileParentId(int userHandle) {
return mInjector.binderWithCleanCallingIdentity(() -> {
UserInfo parentUser = mUserManager.getProfileParent(userHandle);
@@ -8569,7 +8578,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
Objects.requireNonNull(agent, "agent null");
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = admin != null
+ ? getCallerIdentity(admin)
+ : getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
synchronized (getLockObject()) {
final String componentName = agent.flattenToString();
@@ -8769,9 +8783,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
if (packageList != null) {
- int userId = UserHandle.getCallingUserId();
+ int userId = identity.getUserId();
List<AccessibilityServiceInfo> enabledServices = null;
long id = mInjector.binderClearCallingIdentity();
try {
@@ -8801,8 +8816,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
admin.permittedAccessiblityServices = packageList;
saveSettingsLocked(UserHandle.getCallingUserId());
}
@@ -8822,10 +8836,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(identity) || isProfileOwner(identity));
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.permittedAccessiblityServices;
}
}
@@ -8920,17 +8935,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
- final int callingUserId = mInjector.userHandleGetCallingUserId();
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(identity) || isProfileOwner(identity));
+
if (packageList != null) {
List<InputMethodInfo> enabledImes = InputMethodManagerInternal.get()
- .getEnabledInputMethodListAsUser(callingUserId);
+ .getEnabledInputMethodListAsUser(identity.getUserId());
if (enabledImes != null) {
List<String> enabledPackages = new ArrayList<String>();
for (InputMethodInfo ime : enabledImes) {
enabledPackages.add(ime.getPackageName());
}
if (!checkPackagesInPermittedListOrSystem(enabledPackages, packageList,
- callingUserId)) {
+ identity.getUserId())) {
Slog.e(LOG_TAG, "Cannot set permitted input methods, "
+ "because it contains already enabled input method.");
return false;
@@ -8939,10 +8956,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
admin.permittedInputMethods = packageList;
- saveSettingsLocked(callingUserId);
+ saveSettingsLocked(identity.getUserId());
}
final String[] packageArray =
packageList != null ? ((List<String>) packageList).toArray(new String[0]) : null;
@@ -8960,10 +8976,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(identity) || isProfileOwner(identity));
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.permittedInputMethods;
}
}
@@ -9037,17 +9054,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
- final int callingUserId = mInjector.userHandleGetCallingUserId();
- if (!isManagedProfile(callingUserId)) {
+ if (!isManagedProfile(identity.getUserId())) {
return false;
}
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(
- who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
admin.permittedNotificationListeners = packageList;
- saveSettingsLocked(callingUserId);
+ saveSettingsLocked(identity.getUserId());
}
return true;
}
@@ -9058,10 +9074,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(
- who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // API contract is to return null if there are no permitted cross-profile notification
+ // listeners, including in Device Owner mode.
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.permittedNotificationListeners;
}
}
@@ -9922,10 +9940,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public String[] getAccountTypesWithManagementDisabledAsUser(int userId, boolean parent) {
- enforceFullCrossUsersPermission(userId);
if (!mHasFeature) {
return null;
}
+ Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userId));
+
synchronized (getLockObject()) {
final ArraySet<String> resultSet = new ArraySet<>();
@@ -9992,10 +10014,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final int userId = UserHandle.getCallingUserId();
synchronized (getLockObject()) {
+ //TODO: This is a silly access control check. Remove.
if (who != null) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(
+ isProfileOwner(caller) || isDeviceOwner(caller));
}
-
long id = mInjector.binderClearCallingIdentity();
try {
return mIPackageManager.getBlockUninstallForUser(packageName, userId);
@@ -10015,12 +10039,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (admin.disableCallerId != disabled) {
admin.disableCallerId = disabled;
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ saveSettingsLocked(identity.getUserId());
}
}
DevicePolicyEventLogger
@@ -10036,16 +10062,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.disableCallerId;
}
}
@Override
public boolean getCrossProfileCallerIdDisabledForUser(int userId) {
- enforceCrossUsersPermission(userId);
+ Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasCrossUsersPermission(identity, userId));
+
synchronized (getLockObject()) {
ActiveAdmin admin = getProfileOwnerAdminLocked(userId);
return (admin != null) ? admin.disableCallerId : false;
@@ -10058,12 +10090,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (admin.disableContactsSearch != disabled) {
admin.disableContactsSearch = disabled;
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ saveSettingsLocked(identity.getUserId());
}
}
DevicePolicyEventLogger
@@ -10079,16 +10113,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.disableContactsSearch;
}
}
@Override
public boolean getCrossProfileContactsSearchDisabledForUser(int userId) {
- enforceCrossUsersPermission(userId);
+ Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasCrossUsersPermission(identity, userId));
+
synchronized (getLockObject()) {
ActiveAdmin admin = getProfileOwnerAdminLocked(userId);
return (admin != null) ? admin.disableContactsSearch : false;
@@ -10159,12 +10199,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(identity) || isProfileOwner(identity));
+
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (admin.disableBluetoothContactSharing != disabled) {
admin.disableBluetoothContactSharing = disabled;
- saveSettingsLocked(UserHandle.getCallingUserId());
+ saveSettingsLocked(identity.getUserId());
}
}
DevicePolicyEventLogger
@@ -10180,9 +10222,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(identity) || isProfileOwner(identity));
+
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.disableBluetoothContactSharing;
}
}
@@ -12138,13 +12182,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final int userHandle = mInjector.userHandleGetCallingUserId();
- enforceManagedProfile(userHandle, "set organization color");
+ final CallerIdentity identity = getCallerIdentity(who);
+ enforceManagedProfile(identity.getUserId(), "set organization color");
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
admin.organizationColor = color;
- saveSettingsLocked(userHandle);
+ saveSettingsLocked(identity.getUserId());
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_ORGANIZATION_COLOR)
@@ -12157,7 +12200,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return;
}
- enforceFullCrossUsersPermission(userId);
+ Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userId));
+
enforceManageUsers();
enforceManagedProfile(userId, "set organization color");
synchronized (getLockObject()) {
@@ -12173,10 +12220,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
}
Objects.requireNonNull(who, "ComponentName is null");
- enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization color");
+ final CallerIdentity identity = getCallerIdentity(who);
+ enforceManagedProfile(identity.getUserId(), "get organization color");
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.organizationColor;
}
}
@@ -12186,7 +12233,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
enforceManagedProfile(userHandle, "get organization color");
synchronized (getLockObject()) {
ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
@@ -12202,15 +12253,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final int userHandle = mInjector.userHandleGetCallingUserId();
+ final CallerIdentity identity = getCallerIdentity(who);
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (!TextUtils.equals(admin.organizationName, text)) {
admin.organizationName = (text == null || text.length() == 0)
? null : text.toString();
- saveSettingsLocked(userHandle);
+ saveSettingsLocked(identity.getUserId());
}
}
}
@@ -12221,10 +12271,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
- enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization name");
+ final CallerIdentity identity = getCallerIdentity(who);
+ enforceManagedProfile(identity.getUserId(), "get organization name");
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.organizationName;
}
}
@@ -12246,7 +12296,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return null;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
enforceManagedProfile(userHandle, "get organization name");
synchronized (getLockObject()) {
ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
@@ -12260,20 +12314,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public List<String> setMeteredDataDisabledPackages(ComponentName who, List<String> packageNames) {
Objects.requireNonNull(who);
Objects.requireNonNull(packageNames);
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkSecurity(isDeviceOwner(identity) || isProfileOwner(identity),
+ String.format("Admin %s does not own the profile", identity.getComponentName()));
if (!mHasFeature) {
return packageNames;
}
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- final int callingUserId = mInjector.userHandleGetCallingUserId();
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return mInjector.binderWithCleanCallingIdentity(() -> {
- final List<String> excludedPkgs
- = removeInvalidPkgsForMeteredDataRestriction(callingUserId, packageNames);
+ final List<String> excludedPkgs = removeInvalidPkgsForMeteredDataRestriction(
+ identity.getUserId(), packageNames);
admin.meteredDisabledPackages = packageNames;
- pushMeteredDisabledPackagesLocked(callingUserId);
- saveSettingsLocked(callingUserId);
+ pushMeteredDisabledPackagesLocked(identity.getUserId());
+ saveSettingsLocked(identity.getUserId());
return excludedPkgs;
});
}
@@ -12310,9 +12365,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return new ArrayList<>();
}
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkSecurity(isDeviceOwner(identity) || isProfileOwner(identity),
+ String.format("Admin %s does not own the profile", identity.getComponentName()));
+
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.meteredDisabledPackages == null
? new ArrayList<>() : admin.meteredDisabledPackages;
}
@@ -12337,12 +12395,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
- private boolean hasMarkProfileOwnerOnOrganizationOwnedDevicePermission() {
- return mContext.checkCallingPermission(
- permission.MARK_DEVICE_ORGANIZATION_OWNED)
- == PackageManager.PERMISSION_GRANTED;
- }
-
@Override
public void markProfileOwnerOnOrganizationOwnedDevice(ComponentName who, int userId) {
// As the caller is the system, it must specify the component name of the profile owner
@@ -12355,7 +12407,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// Only adb or system apps with the right permission can mark a profile owner on
// organization-owned device.
- if (!(isAdb() || hasMarkProfileOwnerOnOrganizationOwnedDevicePermission())) {
+ if (!(isAdb() || hasCallingPermission(permission.MARK_DEVICE_ORGANIZATION_OWNED))) {
throw new SecurityException(
"Only the system can mark a profile owner of organization-owned device.");
}
@@ -13483,7 +13535,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public StringParceledListSlice getOwnerInstalledCaCerts(@NonNull UserHandle user) {
final int userId = user.getIdentifier();
- enforceProfileOwnerOrFullCrossUsersPermission(userId);
+ final CallerIdentity identity = getCallerIdentity();
+ enforceProfileOwnerOrFullCrossUsersPermission(identity, userId);
synchronized (getLockObject()) {
return new StringParceledListSlice(
new ArrayList<>(getUserData(userId).mOwnerInstalledCaCerts));
@@ -14100,12 +14153,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(
- who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
admin.mCrossProfileCalendarPackages = packageNames;
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ saveSettingsLocked(identity.getUserId());
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_CROSS_PROFILE_CALENDAR_PACKAGES)
@@ -14121,10 +14174,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return Collections.emptyList();
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(
- who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.mCrossProfileCalendarPackages;
}
}
@@ -14136,8 +14189,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Preconditions.checkStringNotEmpty(packageName, "Package name is null or empty");
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasCrossUsersPermission(identity, userHandle));
- enforceCrossUsersPermission(userHandle);
synchronized (getLockObject()) {
if (mInjector.settingsSecureGetIntForUser(
Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED, 0, userHandle) == 0) {
@@ -14159,7 +14215,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return Collections.emptyList();
}
- enforceCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
final ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
if (admin != null) {
@@ -14176,16 +14236,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(packageNames, "Package names is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+
final List<String> previousCrossProfilePackages;
synchronized (getLockObject()) {
- final ActiveAdmin admin =
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
previousCrossProfilePackages = admin.mCrossProfilePackages;
if (packageNames.equals(previousCrossProfilePackages)) {
return;
}
admin.mCrossProfilePackages = packageNames;
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ saveSettingsLocked(identity.getUserId());
}
logSetCrossProfilePackages(who, packageNames);
final CrossProfileApps crossProfileApps = mContext.getSystemService(CrossProfileApps.class);
@@ -14208,10 +14269,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return Collections.emptyList();
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(
- who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.mCrossProfilePackages;
}
}
@@ -14221,7 +14282,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return Collections.emptyList();
}
- enforceAcrossUsersPermissions();
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(
+ isSystemUid(identity) || isRootUid(identity) || hasCallingPermission(
+ permission.INTERACT_ACROSS_USERS) || hasCallingPermission(
+ permission.INTERACT_ACROSS_USERS_FULL) || hasPermissionForPreflight(
+ identity, permission.INTERACT_ACROSS_PROFILES));
synchronized (getLockObject()) {
final List<ActiveAdmin> admins = getProfileOwnerAdminsForCurrentProfileGroup();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
new file mode 100644
index 000000000000..46c9aab5bb97
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
@@ -0,0 +1,324 @@
+/*
+ * 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.devicepolicy;
+
+import static android.app.admin.DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED;
+import static android.app.admin.DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED;
+import static android.app.admin.DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH;
+import static android.app.admin.DevicePolicyManager.EXTRA_BUGREPORT_NOTIFICATION_TYPE;
+import static android.app.admin.DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH;
+import static android.app.admin.DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED;
+import static android.app.admin.DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED;
+import static android.app.admin.DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED;
+
+import android.annotation.IntDef;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.admin.DeviceAdminReceiver;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.format.DateUtils;
+import android.util.Pair;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
+
+import java.io.FileNotFoundException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Class managing bugreport collection upon device owner's request.
+ */
+public class RemoteBugreportManager {
+ private static final String LOG_TAG = DevicePolicyManagerService.LOG_TAG;
+
+ static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport";
+
+ private static final long REMOTE_BUGREPORT_TIMEOUT_MILLIS = 10 * DateUtils.MINUTE_IN_MILLIS;
+ private static final String CTL_STOP = "ctl.stop";
+ private static final String REMOTE_BUGREPORT_SERVICE = "bugreportd";
+ private static final int NOTIFICATION_ID = SystemMessage.NOTE_REMOTE_BUGREPORT;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ NOTIFICATION_BUGREPORT_STARTED,
+ NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED,
+ NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED
+ })
+ @interface RemoteBugreportNotificationType {}
+ private final DevicePolicyManagerService mService;
+ private final DevicePolicyManagerService.Injector mInjector;
+
+ private final AtomicBoolean mRemoteBugreportServiceIsActive = new AtomicBoolean();
+ private final AtomicBoolean mRemoteBugreportSharingAccepted = new AtomicBoolean();
+ private final Context mContext;
+
+ private final Handler mHandler;
+
+ private final Runnable mRemoteBugreportTimeoutRunnable = () -> {
+ if (mRemoteBugreportServiceIsActive.get()) {
+ onBugreportFailed();
+ }
+ };
+
+ private final BroadcastReceiver mRemoteBugreportFinishedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_REMOTE_BUGREPORT_DISPATCH.equals(intent.getAction())
+ && mRemoteBugreportServiceIsActive.get()) {
+ onBugreportFinished(intent);
+ }
+ }
+ };
+
+ private final BroadcastReceiver mRemoteBugreportConsentReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID);
+ if (ACTION_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
+ onBugreportSharingAccepted();
+ } else if (ACTION_BUGREPORT_SHARING_DECLINED.equals(action)) {
+ onBugreportSharingDeclined();
+ }
+ mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
+ }
+ };
+
+ public RemoteBugreportManager(
+ DevicePolicyManagerService service, DevicePolicyManagerService.Injector injector) {
+ mService = service;
+ mInjector = injector;
+ mContext = service.mContext;
+ mHandler = service.mHandler;
+ }
+
+ private Notification buildNotification(@RemoteBugreportNotificationType int type) {
+ final Intent dialogIntent = new Intent(Settings.ACTION_SHOW_REMOTE_BUGREPORT_DIALOG);
+ dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ dialogIntent.putExtra(EXTRA_BUGREPORT_NOTIFICATION_TYPE, type);
+
+ // Fill the component explicitly to prevent the PendingIntent from being intercepted
+ // and fired with crafted target. b/155183624
+ final ActivityInfo targetInfo = dialogIntent.resolveActivityInfo(
+ mContext.getPackageManager(), PackageManager.MATCH_SYSTEM_ONLY);
+ if (targetInfo != null) {
+ dialogIntent.setComponent(targetInfo.getComponentName());
+ } else {
+ Slog.wtf(LOG_TAG, "Failed to resolve intent for remote bugreport dialog");
+ }
+
+ final PendingIntent pendingDialogIntent = PendingIntent.getActivityAsUser(mContext, type,
+ dialogIntent, 0, null, UserHandle.CURRENT);
+
+ final Notification.Builder builder =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+ .setOngoing(true)
+ .setLocalOnly(true)
+ .setContentIntent(pendingDialogIntent)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
+
+ if (type == NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
+ builder.setContentTitle(mContext.getString(
+ R.string.sharing_remote_bugreport_notification_title))
+ .setProgress(0, 0, true);
+ } else if (type == NOTIFICATION_BUGREPORT_STARTED) {
+ builder.setContentTitle(mContext.getString(
+ R.string.taking_remote_bugreport_notification_title))
+ .setProgress(0, 0, true);
+ } else if (type == NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED) {
+ final PendingIntent pendingIntentAccept = PendingIntent.getBroadcast(mContext,
+ NOTIFICATION_ID, new Intent(ACTION_BUGREPORT_SHARING_ACCEPTED),
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ final PendingIntent pendingIntentDecline = PendingIntent.getBroadcast(mContext,
+ NOTIFICATION_ID, new Intent(ACTION_BUGREPORT_SHARING_DECLINED),
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ builder.addAction(new Notification.Action.Builder(null /* icon */, mContext.getString(
+ R.string.decline_remote_bugreport_action), pendingIntentDecline).build())
+ .addAction(new Notification.Action.Builder(null /* icon */, mContext.getString(
+ R.string.share_remote_bugreport_action), pendingIntentAccept).build())
+ .setContentTitle(mContext.getString(
+ R.string.share_remote_bugreport_notification_title))
+ .setContentText(mContext.getString(
+ R.string.share_remote_bugreport_notification_message_finished))
+ .setStyle(new Notification.BigTextStyle().bigText(mContext.getString(
+ R.string.share_remote_bugreport_notification_message_finished)));
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Initiates bugreport collection.
+ * @return whether collection was initiated successfully.
+ */
+ public boolean requestBugreport() {
+ if (mRemoteBugreportServiceIsActive.get()
+ || (mService.getDeviceOwnerRemoteBugreportUriAndHash() != null)) {
+ Slog.d(LOG_TAG, "Remote bugreport wasn't started because there's already one running.");
+ return false;
+ }
+
+ final long callingIdentity = mInjector.binderClearCallingIdentity();
+ try {
+ mInjector.getIActivityManager().requestRemoteBugReport();
+
+ mRemoteBugreportServiceIsActive.set(true);
+ mRemoteBugreportSharingAccepted.set(false);
+ registerRemoteBugreportReceivers();
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
+ buildNotification(NOTIFICATION_BUGREPORT_STARTED), UserHandle.ALL);
+ mHandler.postDelayed(mRemoteBugreportTimeoutRunnable, REMOTE_BUGREPORT_TIMEOUT_MILLIS);
+ return true;
+ } catch (RemoteException re) {
+ // should never happen
+ Slog.e(LOG_TAG, "Failed to make remote calls to start bugreportremote service", re);
+ return false;
+ } finally {
+ mInjector.binderRestoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ private void registerRemoteBugreportReceivers() {
+ try {
+ final IntentFilter filterFinished =
+ new IntentFilter(ACTION_REMOTE_BUGREPORT_DISPATCH, BUGREPORT_MIMETYPE);
+ mContext.registerReceiver(mRemoteBugreportFinishedReceiver, filterFinished);
+ } catch (IntentFilter.MalformedMimeTypeException e) {
+ // should never happen, as setting a constant
+ Slog.w(LOG_TAG, "Failed to set type " + BUGREPORT_MIMETYPE, e);
+ }
+ final IntentFilter filterConsent = new IntentFilter();
+ filterConsent.addAction(ACTION_BUGREPORT_SHARING_DECLINED);
+ filterConsent.addAction(ACTION_BUGREPORT_SHARING_ACCEPTED);
+ mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
+ }
+
+ private void onBugreportFinished(Intent intent) {
+ mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
+ mRemoteBugreportServiceIsActive.set(false);
+ final Uri bugreportUri = intent.getData();
+ String bugreportUriString = null;
+ if (bugreportUri != null) {
+ bugreportUriString = bugreportUri.toString();
+ }
+ final String bugreportHash = intent.getStringExtra(EXTRA_REMOTE_BUGREPORT_HASH);
+ if (mRemoteBugreportSharingAccepted.get()) {
+ shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
+ mInjector.getNotificationManager().cancel(LOG_TAG,
+ NOTIFICATION_ID);
+ } else {
+ mService.setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash);
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
+ buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
+ UserHandle.ALL);
+ }
+ mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
+ }
+
+ private void onBugreportFailed() {
+ mRemoteBugreportServiceIsActive.set(false);
+ mInjector.systemPropertiesSet(CTL_STOP, REMOTE_BUGREPORT_SERVICE);
+ mRemoteBugreportSharingAccepted.set(false);
+ mService.setDeviceOwnerRemoteBugreportUriAndHash(null, null);
+ mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID);
+ final Bundle extras = new Bundle();
+ extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
+ DeviceAdminReceiver.BUGREPORT_FAILURE_FAILED_COMPLETING);
+ mService.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_FAILED, extras);
+ mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
+ mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
+ }
+
+ private void onBugreportSharingAccepted() {
+ mRemoteBugreportSharingAccepted.set(true);
+ final Pair<String, String> uriAndHash = mService.getDeviceOwnerRemoteBugreportUriAndHash();
+ if (uriAndHash != null) {
+ shareBugreportWithDeviceOwnerIfExists(uriAndHash.first, uriAndHash.second);
+ } else if (mRemoteBugreportServiceIsActive.get()) {
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
+ buildNotification(NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED),
+ UserHandle.ALL);
+ }
+ }
+
+ private void onBugreportSharingDeclined() {
+ if (mRemoteBugreportServiceIsActive.get()) {
+ mInjector.systemPropertiesSet(CTL_STOP,
+ REMOTE_BUGREPORT_SERVICE);
+ mRemoteBugreportServiceIsActive.set(false);
+ mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
+ mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
+ }
+ mRemoteBugreportSharingAccepted.set(false);
+ mService.setDeviceOwnerRemoteBugreportUriAndHash(null, null);
+ mService.sendDeviceOwnerCommand(
+ DeviceAdminReceiver.ACTION_BUGREPORT_SHARING_DECLINED, null);
+ }
+
+ private void shareBugreportWithDeviceOwnerIfExists(
+ String bugreportUriString, String bugreportHash) {
+ try {
+ if (bugreportUriString == null) {
+ throw new FileNotFoundException();
+ }
+ final Uri bugreportUri = Uri.parse(bugreportUriString);
+ mService.sendBugreportToDeviceOwner(bugreportUri, bugreportHash);
+ } catch (FileNotFoundException e) {
+ final Bundle extras = new Bundle();
+ extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
+ DeviceAdminReceiver.BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE);
+ mService.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_FAILED, extras);
+ } finally {
+ mRemoteBugreportSharingAccepted.set(false);
+ mService.setDeviceOwnerRemoteBugreportUriAndHash(null, null);
+ }
+ }
+
+ /**
+ * Check if a bugreport was collected but not shared before reboot because the user didn't act
+ * upon sharing notification.
+ */
+ public void checkForPendingBugreportAfterBoot() {
+ if (mService.getDeviceOwnerRemoteBugreportUriAndHash() == null) {
+ return;
+ }
+ final IntentFilter filterConsent = new IntentFilter();
+ filterConsent.addAction(ACTION_BUGREPORT_SHARING_DECLINED);
+ filterConsent.addAction(ACTION_BUGREPORT_SHARING_ACCEPTED);
+ mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
+ buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED), UserHandle.ALL);
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
deleted file mode 100644
index 1630f271a296..000000000000
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.server.devicepolicy;
-
-import android.annotation.IntDef;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.format.DateUtils;
-import android.util.Slog;
-
-import com.android.internal.R;
-import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.notification.SystemNotificationChannels;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Utilities class for the remote bugreport operation.
- */
-class RemoteBugreportUtils {
-
- private static final String TAG = "RemoteBugreportUtils";
- static final int NOTIFICATION_ID = SystemMessage.NOTE_REMOTE_BUGREPORT;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED
- })
- @interface RemoteBugreportNotificationType {}
-
- static final long REMOTE_BUGREPORT_TIMEOUT_MILLIS = 10 * DateUtils.MINUTE_IN_MILLIS;
-
- static final String CTL_STOP = "ctl.stop";
- static final String REMOTE_BUGREPORT_SERVICE = "bugreportd";
-
- static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport";
-
- static Notification buildNotification(Context context,
- @RemoteBugreportNotificationType int type) {
- Intent dialogIntent = new Intent(Settings.ACTION_SHOW_REMOTE_BUGREPORT_DIALOG);
- dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- dialogIntent.putExtra(DevicePolicyManager.EXTRA_BUGREPORT_NOTIFICATION_TYPE, type);
-
- // Fill the component explicitly to prevent the PendingIntent from being intercepted
- // and fired with crafted target. b/155183624
- ActivityInfo targetInfo = dialogIntent.resolveActivityInfo(
- context.getPackageManager(), PackageManager.MATCH_SYSTEM_ONLY);
- if (targetInfo != null) {
- dialogIntent.setComponent(targetInfo.getComponentName());
- } else {
- Slog.wtf(TAG, "Failed to resolve intent for remote bugreport dialog");
- }
-
- PendingIntent pendingDialogIntent = PendingIntent.getActivityAsUser(context, type,
- dialogIntent, 0, null, UserHandle.CURRENT);
-
- Notification.Builder builder =
- new Notification.Builder(context, SystemNotificationChannels.DEVICE_ADMIN)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
- .setOngoing(true)
- .setLocalOnly(true)
- .setContentIntent(pendingDialogIntent)
- .setColor(context.getColor(
- com.android.internal.R.color.system_notification_accent_color));
-
- if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
- builder.setContentTitle(context.getString(
- R.string.sharing_remote_bugreport_notification_title))
- .setProgress(0, 0, true);
- } else if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED) {
- builder.setContentTitle(context.getString(
- R.string.taking_remote_bugreport_notification_title))
- .setProgress(0, 0, true);
- } else if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED) {
- PendingIntent pendingIntentAccept = PendingIntent.getBroadcast(context, NOTIFICATION_ID,
- new Intent(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED),
- PendingIntent.FLAG_CANCEL_CURRENT);
- PendingIntent pendingIntentDecline = PendingIntent.getBroadcast(context,
- NOTIFICATION_ID, new Intent(
- DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED),
- PendingIntent.FLAG_CANCEL_CURRENT);
- builder.addAction(new Notification.Action.Builder(null /* icon */, context.getString(
- R.string.decline_remote_bugreport_action), pendingIntentDecline).build())
- .addAction(new Notification.Action.Builder(null /* icon */, context.getString(
- R.string.share_remote_bugreport_action), pendingIntentAccept).build())
- .setContentTitle(context.getString(
- R.string.share_remote_bugreport_notification_title))
- .setContentText(context.getString(
- R.string.share_remote_bugreport_notification_message_finished))
- .setStyle(new Notification.BigTextStyle().bigText(context.getString(
- R.string.share_remote_bugreport_notification_message_finished)));
- }
-
- return builder.build();
- }
-}
-
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 0ae10b6dc3b5..41945a276fde 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -237,11 +237,9 @@ binder::Status BinderIncrementalService::unlink(int32_t storageId, const std::st
return ok();
}
-binder::Status BinderIncrementalService::isFileRangeLoaded(int32_t storageId,
- const std::string& path, int64_t start,
- int64_t end, bool* _aidl_return) {
- // TODO: implement
- *_aidl_return = false;
+binder::Status BinderIncrementalService::getLoadingProgress(int32_t storageId,
+ float* _aidl_return) {
+ *_aidl_return = mImpl.getLoadingProgress(storageId);
return ok();
}
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 10154946d3ee..8b40350468ce 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -66,8 +66,7 @@ public:
int32_t destStorageId, const std::string& destPath,
int32_t* _aidl_return) final;
binder::Status unlink(int32_t storageId, const std::string& path, int32_t* _aidl_return) final;
- binder::Status isFileRangeLoaded(int32_t storageId, const std::string& path, int64_t start,
- int64_t end, bool* _aidl_return) final;
+ binder::Status getLoadingProgress(int32_t storageId, float* _aidl_return) final;
binder::Status getMetadataByPath(int32_t storageId, const std::string& path,
std::vector<uint8_t>* _aidl_return) final;
binder::Status getMetadataById(int32_t storageId, const std::vector<uint8_t>& id,
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index f7082a9a1a0c..ba6ae9262aea 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -37,7 +37,6 @@
#include "Metadata.pb.h"
using namespace std::literals;
-namespace fs = std::filesystem;
constexpr const char* kDataUsageStats = "android.permission.LOADER_USAGE_STATS";
constexpr const char* kOpUsage = "android:loader_usage_stats";
@@ -276,6 +275,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v
mJni(sm.getJni()),
mLooper(sm.getLooper()),
mTimedQueue(sm.getTimedQueue()),
+ mFs(sm.getFs()),
mIncrementalDir(rootDir) {
CHECK(mVold) << "Vold service is unavailable";
CHECK(mDataLoaderManager) << "DataLoaderManagerService is unavailable";
@@ -283,6 +283,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v
CHECK(mJni) << "JNI is unavailable";
CHECK(mLooper) << "Looper is unavailable";
CHECK(mTimedQueue) << "TimedQueue is unavailable";
+ CHECK(mFs) << "Fs is unavailable";
mJobQueue.reserve(16);
mJobProcessor = std::thread([this]() {
@@ -344,7 +345,8 @@ void IncrementalService::onDump(int fd) {
}
dprintf(fd, " storages (%d): {\n", int(mnt.storages.size()));
for (auto&& [storageId, storage] : mnt.storages) {
- dprintf(fd, " [%d] -> [%s]\n", storageId, storage.name.c_str());
+ dprintf(fd, " [%d] -> [%s] (%d %% loaded) \n", storageId, storage.name.c_str(),
+ (int)(getLoadingProgressFromPath(mnt, storage.name.c_str()) * 100));
}
dprintf(fd, " }\n");
@@ -1671,6 +1673,45 @@ bool IncrementalService::waitForNativeBinariesExtraction(StorageId storage) {
return mRunning;
}
+float IncrementalService::getLoadingProgress(StorageId storage) const {
+ std::unique_lock l(mLock);
+ const auto ifs = getIfsLocked(storage);
+ if (!ifs) {
+ LOG(ERROR) << "getLoadingProgress failed, invalid storageId: " << storage;
+ return -EINVAL;
+ }
+ const auto storageInfo = ifs->storages.find(storage);
+ if (storageInfo == ifs->storages.end()) {
+ LOG(ERROR) << "getLoadingProgress failed, no storage: " << storage;
+ return -EINVAL;
+ }
+ l.unlock();
+ return getLoadingProgressFromPath(*ifs, storageInfo->second.name);
+}
+
+float IncrementalService::getLoadingProgressFromPath(const IncFsMount& ifs,
+ std::string_view storagePath) const {
+ size_t totalBlocks = 0, filledBlocks = 0;
+ const auto filePaths = mFs->listFilesRecursive(storagePath);
+ for (const auto& filePath : filePaths) {
+ const auto [filledBlocksCount, totalBlocksCount] =
+ mIncFs->countFilledBlocks(ifs.control, filePath);
+ if (filledBlocksCount < 0) {
+ LOG(ERROR) << "getLoadingProgress failed to get filled blocks count for: " << filePath
+ << " errno: " << filledBlocksCount;
+ return filledBlocksCount;
+ }
+ totalBlocks += totalBlocksCount;
+ filledBlocks += filledBlocksCount;
+ }
+
+ if (totalBlocks == 0) {
+ LOG(ERROR) << "getLoadingProgress failed to get total num of blocks";
+ return -EINVAL;
+ }
+ return (float)filledBlocks / (float)totalBlocks;
+}
+
bool IncrementalService::perfLoggingEnabled() {
static const bool enabled = base::GetBoolProperty("incremental.perflogging", false);
return enabled;
@@ -2029,11 +2070,13 @@ void IncrementalService::DataLoaderStub::updateHealthStatus(bool baseline) {
// Healthcheck depends on timestamp of the oldest pending read.
// To get it, we need to re-open a pendingReads FD to get a full list of reads.
- // Additionally we need to re-register for epoll with fresh FDs in case there are no reads.
+ // Additionally we need to re-register for epoll with fresh FDs in case there are no
+ // reads.
const auto now = Clock::now();
const auto kernelTsUs = getOldestPendingReadTs();
if (baseline) {
- // Updating baseline only on looper/epoll callback, i.e. on new set of pending reads.
+ // Updating baseline only on looper/epoll callback, i.e. on new set of pending
+ // reads.
mHealthBase = {now, kernelTsUs};
}
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index a6cc94639c8a..cd6bfedb8a9e 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -132,9 +132,7 @@ public:
std::string_view newPath);
int unlink(StorageId storage, std::string_view path);
- bool isRangeLoaded(StorageId storage, FileId file, std::pair<BlockIndex, BlockIndex> range) {
- return false;
- }
+ float getLoadingProgress(StorageId storage) const;
RawMetadata getMetadata(StorageId storage, std::string_view path) const;
RawMetadata getMetadata(StorageId storage, FileId node) const;
@@ -341,6 +339,8 @@ private:
int makeDirs(const IncFsMount& ifs, StorageId storageId, std::string_view path, int mode);
binder::Status applyStorageParams(IncFsMount& ifs, bool enableReadLogs);
+ float getLoadingProgressFromPath(const IncFsMount& ifs, std::string_view path) const;
+
void registerAppOpsCallback(const std::string& packageName);
bool unregisterAppOpsCallback(const std::string& packageName);
void onAppOpChanged(const std::string& packageName);
@@ -363,6 +363,7 @@ private:
const std::unique_ptr<JniWrapper> mJni;
const std::unique_ptr<LooperWrapper> mLooper;
const std::unique_ptr<TimedQueueWrapper> mTimedQueue;
+ const std::unique_ptr<FsWrapper> mFs;
const std::string mIncrementalDir;
mutable std::mutex mLock;
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 99a35adb5074..1ed46c49c5e1 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -25,6 +25,7 @@
#include <binder/AppOpsManager.h>
#include <utils/String16.h>
+#include <filesystem>
#include <thread>
#include "IncrementalServiceValidation.h"
@@ -165,6 +166,29 @@ public:
FileId getFileId(const Control& control, std::string_view path) const final {
return incfs::getFileId(control, path);
}
+ std::pair<IncFsBlockIndex, IncFsBlockIndex> countFilledBlocks(
+ const Control& control, std::string_view path) const final {
+ const auto fileId = incfs::getFileId(control, path);
+ const auto fd = incfs::openForSpecialOps(control, fileId);
+ int res = fd.get();
+ if (!fd.ok()) {
+ return {res, res};
+ }
+ const auto ranges = incfs::getFilledRanges(res);
+ res = ranges.first;
+ if (res) {
+ return {res, res};
+ }
+ const auto totalBlocksCount = ranges.second.internalRawRanges().endIndex;
+ int filledBlockCount = 0;
+ for (const auto& dataRange : ranges.second.dataRanges()) {
+ filledBlockCount += dataRange.size();
+ }
+ for (const auto& hashRange : ranges.second.hashRanges()) {
+ filledBlockCount += hashRange.size();
+ }
+ return {filledBlockCount, totalBlocksCount};
+ }
ErrorCode link(const Control& control, std::string_view from, std::string_view to) const final {
return incfs::link(control, from, to);
}
@@ -265,6 +289,23 @@ private:
std::thread mThread;
};
+class RealFsWrapper : public FsWrapper {
+public:
+ RealFsWrapper() = default;
+ ~RealFsWrapper() = default;
+
+ std::vector<std::string> listFilesRecursive(std::string_view directoryPath) const final {
+ std::vector<std::string> files;
+ for (const auto& entry : std::filesystem::recursive_directory_iterator(directoryPath)) {
+ if (!entry.is_regular_file()) {
+ continue;
+ }
+ files.push_back(entry.path().c_str());
+ }
+ return files;
+ }
+};
+
RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env)
: mServiceManager(std::move(serviceManager)), mJvm(RealJniWrapper::getJvm(env)) {}
@@ -316,6 +357,10 @@ std::unique_ptr<TimedQueueWrapper> RealServiceManager::getTimedQueue() {
return std::make_unique<RealTimedQueueWrapper>(mJvm);
}
+std::unique_ptr<FsWrapper> RealServiceManager::getFs() {
+ return std::make_unique<RealFsWrapper>();
+}
+
static JavaVM* getJavaVm(JNIEnv* env) {
CHECK(env);
JavaVM* jvm = nullptr;
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index 8cd726fdc0f1..82a170470fee 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -91,6 +91,8 @@ public:
virtual incfs::RawMetadata getMetadata(const Control& control, FileId fileid) const = 0;
virtual incfs::RawMetadata getMetadata(const Control& control, std::string_view path) const = 0;
virtual FileId getFileId(const Control& control, std::string_view path) const = 0;
+ virtual std::pair<IncFsBlockIndex, IncFsBlockIndex> countFilledBlocks(
+ const Control& control, std::string_view path) const = 0;
virtual ErrorCode link(const Control& control, std::string_view from,
std::string_view to) const = 0;
virtual ErrorCode unlink(const Control& control, std::string_view path) const = 0;
@@ -106,7 +108,8 @@ public:
virtual ~AppOpsManagerWrapper() = default;
virtual binder::Status checkPermission(const char* permission, const char* operation,
const char* package) const = 0;
- virtual void startWatchingMode(int32_t op, const String16& packageName, const sp<IAppOpsCallback>& callback) = 0;
+ virtual void startWatchingMode(int32_t op, const String16& packageName,
+ const sp<IAppOpsCallback>& callback) = 0;
virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0;
};
@@ -134,6 +137,12 @@ public:
virtual void stop() = 0;
};
+class FsWrapper {
+public:
+ virtual ~FsWrapper() = default;
+ virtual std::vector<std::string> listFilesRecursive(std::string_view directoryPath) const = 0;
+};
+
class ServiceManagerWrapper {
public:
virtual ~ServiceManagerWrapper() = default;
@@ -144,6 +153,7 @@ public:
virtual std::unique_ptr<JniWrapper> getJni() = 0;
virtual std::unique_ptr<LooperWrapper> getLooper() = 0;
virtual std::unique_ptr<TimedQueueWrapper> getTimedQueue() = 0;
+ virtual std::unique_ptr<FsWrapper> getFs() = 0;
};
// --- Real stuff ---
@@ -159,6 +169,7 @@ public:
std::unique_ptr<JniWrapper> getJni() final;
std::unique_ptr<LooperWrapper> getLooper() final;
std::unique_ptr<TimedQueueWrapper> getTimedQueue() final;
+ std::unique_ptr<FsWrapper> getFs() final;
private:
template <class INTERFACE>
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 1ae9e256c9f4..44cef49a716c 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -54,8 +54,10 @@ public:
MOCK_CONST_METHOD1(unmountIncFs, binder::Status(const std::string& dir));
MOCK_CONST_METHOD2(bindMount,
binder::Status(const std::string& sourceDir, const std::string& argetDir));
- MOCK_CONST_METHOD2(setIncFsMountOptions,
- binder::Status(const ::android::os::incremental::IncrementalFileSystemControlParcel&, bool));
+ MOCK_CONST_METHOD2(
+ setIncFsMountOptions,
+ binder::Status(const ::android::os::incremental::IncrementalFileSystemControlParcel&,
+ bool));
void mountIncFsFails() {
ON_CALL(*this, mountIncFs(_, _, _, _))
@@ -80,8 +82,8 @@ public:
}
void setIncFsMountOptionsFails() const {
ON_CALL(*this, setIncFsMountOptions(_, _))
- .WillByDefault(
- Return(binder::Status::fromExceptionCode(1, String8("failed to set options"))));
+ .WillByDefault(Return(
+ binder::Status::fromExceptionCode(1, String8("failed to set options"))));
}
void setIncFsMountOptionsSuccess() {
ON_CALL(*this, setIncFsMountOptions(_, _)).WillByDefault(Return(binder::Status::ok()));
@@ -280,8 +282,12 @@ public:
MOCK_CONST_METHOD2(getMetadata, RawMetadata(const Control& control, FileId fileid));
MOCK_CONST_METHOD2(getMetadata, RawMetadata(const Control& control, std::string_view path));
MOCK_CONST_METHOD2(getFileId, FileId(const Control& control, std::string_view path));
+ MOCK_CONST_METHOD2(countFilledBlocks,
+ std::pair<IncFsBlockIndex, IncFsBlockIndex>(const Control& control,
+ std::string_view path));
MOCK_CONST_METHOD3(link,
- ErrorCode(const Control& control, std::string_view from, std::string_view to));
+ ErrorCode(const Control& control, std::string_view from,
+ std::string_view to));
MOCK_CONST_METHOD2(unlink, ErrorCode(const Control& control, std::string_view path));
MOCK_CONST_METHOD2(openForSpecialOps, base::unique_fd(const Control& control, FileId id));
MOCK_CONST_METHOD1(writeBlocks, ErrorCode(std::span<const DataBlock> blocks));
@@ -293,6 +299,19 @@ public:
void makeFileFails() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(-1)); }
void makeFileSuccess() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(0)); }
+
+ void countFilledBlocksSuccess() {
+ ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(1, 2)));
+ }
+
+ void countFilledBlocksFails() {
+ ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(-1, -1)));
+ }
+
+ void countFilledBlocksEmpty() {
+ ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(0, 0)));
+ }
+
void openMountSuccess() {
ON_CALL(*this, openMount(_)).WillByDefault(Invoke(this, &MockIncFs::openMountForHealth));
}
@@ -447,6 +466,21 @@ public:
Job mWhat;
};
+class MockFsWrapper : public FsWrapper {
+public:
+ MOCK_CONST_METHOD1(listFilesRecursive, std::vector<std::string>(std::string_view));
+ void hasNoFile() {
+ ON_CALL(*this, listFilesRecursive(_)).WillByDefault(Return(std::vector<std::string>()));
+ }
+ void hasFiles() {
+ ON_CALL(*this, listFilesRecursive(_))
+ .WillByDefault(Invoke(this, &MockFsWrapper::fakeFiles));
+ }
+ std::vector<std::string> fakeFiles(std::string_view directoryPath) {
+ return {"base.apk", "split.apk", "lib/a.so"};
+ }
+};
+
class MockStorageHealthListener : public os::incremental::BnStorageHealthListener {
public:
MOCK_METHOD2(onHealthStatus, binder::Status(int32_t storageId, int32_t status));
@@ -474,23 +508,28 @@ public:
std::unique_ptr<MockAppOpsManager> appOpsManager,
std::unique_ptr<MockJniWrapper> jni,
std::unique_ptr<MockLooperWrapper> looper,
- std::unique_ptr<MockTimedQueueWrapper> timedQueue)
+ std::unique_ptr<MockTimedQueueWrapper> timedQueue,
+ std::unique_ptr<MockFsWrapper> fs)
: mVold(std::move(vold)),
mDataLoaderManager(std::move(dataLoaderManager)),
mIncFs(std::move(incfs)),
mAppOpsManager(std::move(appOpsManager)),
mJni(std::move(jni)),
mLooper(std::move(looper)),
- mTimedQueue(std::move(timedQueue)) {}
+ mTimedQueue(std::move(timedQueue)),
+ mFs(std::move(fs)) {}
std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); }
std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final {
return std::move(mDataLoaderManager);
}
std::unique_ptr<IncFsWrapper> getIncFs() final { return std::move(mIncFs); }
- std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final { return std::move(mAppOpsManager); }
+ std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final {
+ return std::move(mAppOpsManager);
+ }
std::unique_ptr<JniWrapper> getJni() final { return std::move(mJni); }
std::unique_ptr<LooperWrapper> getLooper() final { return std::move(mLooper); }
std::unique_ptr<TimedQueueWrapper> getTimedQueue() final { return std::move(mTimedQueue); }
+ std::unique_ptr<FsWrapper> getFs() final { return std::move(mFs); }
private:
std::unique_ptr<MockVoldService> mVold;
@@ -500,6 +539,7 @@ private:
std::unique_ptr<MockJniWrapper> mJni;
std::unique_ptr<MockLooperWrapper> mLooper;
std::unique_ptr<MockTimedQueueWrapper> mTimedQueue;
+ std::unique_ptr<MockFsWrapper> mFs;
};
// --- IncrementalServiceTest ---
@@ -523,6 +563,8 @@ public:
mLooper = looper.get();
auto timedQueue = std::make_unique<NiceMock<MockTimedQueueWrapper>>();
mTimedQueue = timedQueue.get();
+ auto fs = std::make_unique<NiceMock<MockFsWrapper>>();
+ mFs = fs.get();
mIncrementalService =
std::make_unique<IncrementalService>(MockServiceManager(std::move(vold),
std::move(
@@ -531,12 +573,14 @@ public:
std::move(appOps),
std::move(jni),
std::move(looper),
- std::move(timedQueue)),
+ std::move(timedQueue),
+ std::move(fs)),
mRootDir.path);
mDataLoaderParcel.packageName = "com.test";
mDataLoaderParcel.arguments = "uri";
mDataLoaderManager->unbindFromDataLoaderSuccess();
mIncrementalService->onSystemReady();
+ setupSuccess();
}
void setUpExistingMountDir(const std::string& rootDir) {
@@ -560,6 +604,14 @@ public:
.WillByDefault(Invoke(mIncFs, &MockIncFs::getStorageMetadata));
}
+ void setupSuccess() {
+ mVold->mountIncFsSuccess();
+ mIncFs->makeFileSuccess();
+ mVold->bindMountSuccess();
+ mDataLoaderManager->bindToDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
+ }
+
protected:
NiceMock<MockVoldService>* mVold = nullptr;
NiceMock<MockIncFs>* mIncFs = nullptr;
@@ -568,6 +620,7 @@ protected:
NiceMock<MockJniWrapper>* mJni = nullptr;
NiceMock<MockLooperWrapper>* mLooper = nullptr;
NiceMock<MockTimedQueueWrapper>* mTimedQueue = nullptr;
+ NiceMock<MockFsWrapper>* mFs = nullptr;
NiceMock<MockDataLoader>* mDataLoader = nullptr;
std::unique_ptr<IncrementalService> mIncrementalService;
TemporaryDir mRootDir;
@@ -641,11 +694,6 @@ TEST_F(IncrementalServiceTest, testCreateStoragePrepareDataLoaderFails) {
}
TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -661,11 +709,6 @@ TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) {
}
TEST_F(IncrementalServiceTest, testDataLoaderDestroyed) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(2);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
@@ -682,12 +725,7 @@ TEST_F(IncrementalServiceTest, testDataLoaderDestroyed) {
}
TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mDataLoader->initializeCreateOkNoStatus();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -705,12 +743,7 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) {
}
TEST_F(IncrementalServiceTest, testStartDataLoaderPendingStart) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mDataLoader->initializeCreateOkNoStatus();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
@@ -727,12 +760,7 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderPendingStart) {
}
TEST_F(IncrementalServiceTest, testStartDataLoaderCreateUnavailable) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mDataLoader->initializeCreateOkNoStatus();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -748,14 +776,10 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderCreateUnavailable) {
}
TEST_F(IncrementalServiceTest, testStartDataLoaderRecreateOnPendingReads) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mIncFs->openMountSuccess();
mIncFs->waitForPendingReadsSuccess();
- mVold->bindMountSuccess();
+ mIncFs->openMountSuccess();
mDataLoader->initializeCreateOkNoStatus();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
+
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(2);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(2);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
@@ -776,12 +800,8 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderRecreateOnPendingReads) {
}
TEST_F(IncrementalServiceTest, testStartDataLoaderUnhealthyStorage) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
mIncFs->openMountSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
+
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -906,13 +926,9 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderUnhealthyStorage) {
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mVold->setIncFsMountOptionsSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionSuccess();
+
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// We are calling setIncFsMountOptions(true).
@@ -930,13 +946,9 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndDisabled) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mVold->setIncFsMountOptionsSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionSuccess();
+
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// Enabling and then disabling readlogs.
@@ -958,14 +970,10 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndDisabled) {
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChanged) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mVold->setIncFsMountOptionsSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionSuccess();
mAppOpsManager->initializeStartWatchingMode();
+
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// We are calling setIncFsMountOptions(true).
@@ -987,12 +995,8 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChang
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsCheckPermissionFails) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionFails();
+
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// checkPermission fails, no calls to set opitions, start or stop WatchingMode.
@@ -1008,13 +1012,9 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsCheckPermissionFails) {
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mVold->setIncFsMountOptionsFails();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionSuccess();
+
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// We are calling setIncFsMountOptions.
@@ -1031,11 +1031,6 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) {
}
TEST_F(IncrementalServiceTest, testMakeDirectory) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
TemporaryDir tempDir;
int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
IncrementalService::CreateOptions::CreateNew,
@@ -1055,11 +1050,6 @@ TEST_F(IncrementalServiceTest, testMakeDirectory) {
}
TEST_F(IncrementalServiceTest, testMakeDirectories) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
TemporaryDir tempDir;
int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
IncrementalService::CreateOptions::CreateNew,
@@ -1078,4 +1068,51 @@ TEST_F(IncrementalServiceTest, testMakeDirectories) {
auto res = mIncrementalService->makeDirs(storageId, dir_path, 0555);
ASSERT_EQ(res, 0);
}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithNoFile) {
+ mIncFs->countFilledBlocksSuccess();
+ mFs->hasNoFile();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ ASSERT_EQ(-EINVAL, mIncrementalService->getLoadingProgress(storageId));
+}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithFailedRanges) {
+ mIncFs->countFilledBlocksFails();
+ mFs->hasFiles();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
+ ASSERT_EQ(-1, mIncrementalService->getLoadingProgress(storageId));
+}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithEmptyRanges) {
+ mIncFs->countFilledBlocksEmpty();
+ mFs->hasFiles();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(3);
+ ASSERT_EQ(-EINVAL, mIncrementalService->getLoadingProgress(storageId));
+}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccess) {
+ mIncFs->countFilledBlocksSuccess();
+ mFs->hasFiles();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(3);
+ ASSERT_EQ(0.5, mIncrementalService->getLoadingProgress(storageId));
+}
} // namespace android::os::incremental
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index 4b25890e5fdb..5fa809fc89af 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -204,10 +204,10 @@ public class CrossProfileAppsServiceImplRoboTest {
CROSS_PROFILE_APP_PACKAGE_NAME, PERSONAL_PROFILE_UID, PERSONAL_PROFILE_USER_ID);
ShadowApplicationPackageManager.setPackageUidAsUser(
CROSS_PROFILE_APP_PACKAGE_NAME, WORK_PROFILE_UID, WORK_PROFILE_USER_ID);
- when(mPackageManagerInternal.getPackageUidInternal(
+ when(mPackageManagerInternal.getPackageUid(
CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, PERSONAL_PROFILE_USER_ID))
.thenReturn(PERSONAL_PROFILE_UID);
- when(mPackageManagerInternal.getPackageUidInternal(
+ when(mPackageManagerInternal.getPackageUid(
CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, WORK_PROFILE_USER_ID))
.thenReturn(WORK_PROFILE_UID);
}
diff --git a/services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java b/services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java
index 80373ac66109..f9dd7dc86ad5 100644
--- a/services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java
+++ b/services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java
@@ -23,6 +23,8 @@ import static org.junit.Assert.assertNotEquals;
import static java.util.Collections.singletonList;
+import android.os.UserHandle;
+
import org.junit.Test;
import java.util.List;
@@ -33,6 +35,10 @@ public class LocationTimeZoneEventTest {
private static final List<String> ARBITRARY_TIME_ZONE_IDS = singletonList("Europe/London");
+ private static final UserHandle ARBITRARY_USER_HANDLE = UserHandle.SYSTEM;
+ private static final UserHandle ARBITRARY_USER_HANDLE2 =
+ UserHandle.of(ARBITRARY_USER_HANDLE.getIdentifier() + 1);
+
@Test(expected = RuntimeException.class)
public void testSetInvalidEventType() {
new LocationTimeZoneEvent.Builder().setEventType(Integer.MAX_VALUE);
@@ -41,6 +47,7 @@ public class LocationTimeZoneEventTest {
@Test(expected = RuntimeException.class)
public void testBuildUnsetEventType() {
new LocationTimeZoneEvent.Builder()
+ .setUserHandle(ARBITRARY_USER_HANDLE)
.setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS)
.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS)
.build();
@@ -49,6 +56,7 @@ public class LocationTimeZoneEventTest {
@Test(expected = RuntimeException.class)
public void testInvalidTimeZoneIds() {
new LocationTimeZoneEvent.Builder()
+ .setUserHandle(ARBITRARY_USER_HANDLE)
.setEventType(LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN)
.setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS)
.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS)
@@ -58,6 +66,7 @@ public class LocationTimeZoneEventTest {
@Test
public void testEquals() {
LocationTimeZoneEvent.Builder builder1 = new LocationTimeZoneEvent.Builder()
+ .setUserHandle(ARBITRARY_USER_HANDLE)
.setEventType(LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN)
.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS);
{
@@ -66,6 +75,7 @@ public class LocationTimeZoneEventTest {
}
LocationTimeZoneEvent.Builder builder2 = new LocationTimeZoneEvent.Builder()
+ .setUserHandle(ARBITRARY_USER_HANDLE)
.setEventType(LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN)
.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS);
{
@@ -75,6 +85,22 @@ public class LocationTimeZoneEventTest {
assertEquals(two, one);
}
+ builder1.setUserHandle(ARBITRARY_USER_HANDLE2);
+ {
+ LocationTimeZoneEvent one = builder1.build();
+ LocationTimeZoneEvent two = builder2.build();
+ assertNotEquals(one, two);
+ assertNotEquals(two, one);
+ }
+
+ builder2.setUserHandle(ARBITRARY_USER_HANDLE2);
+ {
+ LocationTimeZoneEvent one = builder1.build();
+ LocationTimeZoneEvent two = builder2.build();
+ assertEquals(one, two);
+ assertEquals(two, one);
+ }
+
builder1.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS + 1);
{
LocationTimeZoneEvent one = builder1.build();
@@ -127,6 +153,7 @@ public class LocationTimeZoneEventTest {
@Test
public void testParcelable() {
LocationTimeZoneEvent.Builder builder = new LocationTimeZoneEvent.Builder()
+ .setUserHandle(ARBITRARY_USER_HANDLE)
.setEventType(LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE)
.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS);
assertRoundTripParcelable(builder.build());
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 32afe8244eb6..e6fc792c6a9d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4465,6 +4465,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+ mServiceContext.permissions.add(permission.INTERACT_ACROSS_USERS_FULL);
// Even if the caller is the managed profile, the current user is the user 0
when(getServices().iactivityManager.getCurrentUser())
@@ -5694,6 +5695,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
final long ident = mServiceContext.binder.clearCallingIdentity();
configureContextForAccess(mServiceContext, true);
+ mServiceContext.permissions.add(permission.MARK_DEVICE_ORGANIZATION_OWNED);
mServiceContext.binder.callingUid =
UserHandle.getUid(CALLER_USER_HANDLE,
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index ce7ac9e796d2..09b6d7b0cd7e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -259,18 +259,7 @@ public class DpmMockContext extends MockContext {
@Override
public int checkPermission(String permission, int pid, int uid) {
- if (UserHandle.isSameApp(binder.getCallingUid(), SYSTEM_UID)) {
- return PackageManager.PERMISSION_GRANTED; // Assume system has all permissions.
- }
- List<String> permissions = binder.callingPermissions.get(binder.getCallingUid());
- if (permissions == null) {
- permissions = callerPermissions;
- }
- if (permissions.contains(permission)) {
- return PackageManager.PERMISSION_GRANTED;
- } else {
- return PackageManager.PERMISSION_DENIED;
- }
+ return checkPermission(permission);
}
@Override
@@ -480,11 +469,32 @@ public class DpmMockContext extends MockContext {
@Override
public int checkCallingPermission(String permission) {
- return spiedContext.checkCallingPermission(permission);
+ return checkPermission(permission);
+ }
+
+ @Override
+ public int checkCallingOrSelfPermission(String permission) {
+ return checkPermission(permission);
}
@Override
public void startActivityAsUser(Intent intent, UserHandle userHandle) {
spiedContext.startActivityAsUser(intent, userHandle);
}
+
+ private int checkPermission(String permission) {
+ if (UserHandle.isSameApp(binder.getCallingUid(), SYSTEM_UID)) {
+ return PackageManager.PERMISSION_GRANTED; // Assume system has all permissions.
+ }
+ List<String> permissions = binder.callingPermissions.get(binder.getCallingUid());
+ if (permissions == null) {
+ permissions = callerPermissions;
+ }
+ if (permissions.contains(permission)) {
+ return PackageManager.PERMISSION_GRANTED;
+ } else {
+ return PackageManager.PERMISSION_DENIED;
+ }
+ }
+
}
diff --git a/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java b/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java
index 0219f2201675..4c3674767e97 100644
--- a/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java
@@ -15,13 +15,15 @@
*/
package com.android.server.job;
-import android.util.KeyValueListParser;
+import android.annotation.Nullable;
+import android.provider.DeviceConfig;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.job.JobSchedulerService.MaxJobCounts;
+import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -29,19 +31,32 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class MaxJobCountsTest {
+ @After
+ public void tearDown() throws Exception {
+ resetConfig();
+ }
+
+ private void resetConfig() {
+ // DeviceConfig.resetToDefaults() doesn't work here. Need to reset constants manually.
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, "total", "", false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, "maxbg", "", false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, "minbg", "", false);
+ }
- private void check(String config,
+ private void check(@Nullable DeviceConfig.Properties config,
int defaultTotal, int defaultMaxBg, int defaultMinBg,
- int expectedTotal, int expectedMaxBg, int expectedMinBg) {
- final KeyValueListParser parser = new KeyValueListParser(',');
- parser.setString(config);
+ int expectedTotal, int expectedMaxBg, int expectedMinBg) throws Exception {
+ resetConfig();
+ if (config != null) {
+ DeviceConfig.setProperties(config);
+ }
final MaxJobCounts counts = new JobSchedulerService.MaxJobCounts(
defaultTotal, "total",
defaultMaxBg, "maxbg",
defaultMinBg, "minbg");
- counts.parse(parser);
+ counts.update();
Assert.assertEquals(expectedTotal, counts.getMaxTotal());
Assert.assertEquals(expectedMaxBg, counts.getMaxBg());
@@ -49,24 +64,35 @@ public class MaxJobCountsTest {
}
@Test
- public void test() {
+ public void test() throws Exception {
// Tests with various combinations.
- check("", /*default*/ 5, 1, 0, /*expected*/ 5, 1, 0);
- check("", /*default*/ 5, 0, 0, /*expected*/ 5, 1, 0);
- check("", /*default*/ 0, 0, 0, /*expected*/ 1, 1, 0);
- check("", /*default*/ -1, -1, -1, /*expected*/ 1, 1, 0);
- check("", /*default*/ 5, 5, 5, /*expected*/ 5, 5, 4);
- check("", /*default*/ 6, 5, 6, /*expected*/ 6, 5, 5);
- check("", /*default*/ 4, 5, 6, /*expected*/ 4, 4, 3);
- check("", /*default*/ 5, 1, 1, /*expected*/ 5, 1, 1);
- check("", /*default*/ 15, 15, 15, /*expected*/ 15, 15, 14);
- check("", /*default*/ 16, 16, 16, /*expected*/ 16, 16, 15);
- check("", /*default*/ 20, 20, 20, /*expected*/ 16, 16, 15);
+ check(null, /*default*/ 5, 1, 0, /*expected*/ 5, 1, 0);
+ check(null, /*default*/ 5, 0, 0, /*expected*/ 5, 1, 0);
+ check(null, /*default*/ 0, 0, 0, /*expected*/ 1, 1, 0);
+ check(null, /*default*/ -1, -1, -1, /*expected*/ 1, 1, 0);
+ check(null, /*default*/ 5, 5, 5, /*expected*/ 5, 5, 4);
+ check(null, /*default*/ 6, 5, 6, /*expected*/ 6, 5, 5);
+ check(null, /*default*/ 4, 5, 6, /*expected*/ 4, 4, 3);
+ check(null, /*default*/ 5, 1, 1, /*expected*/ 5, 1, 1);
+ check(null, /*default*/ 15, 15, 15, /*expected*/ 15, 15, 14);
+ check(null, /*default*/ 16, 16, 16, /*expected*/ 16, 16, 15);
+ check(null, /*default*/ 20, 20, 20, /*expected*/ 16, 16, 15);
// Test for overriding with a setting string.
- check("total=5,maxbg=4,minbg=3", /*default*/ 9, 9, 9, /*expected*/ 5, 4, 3);
- check("total=5", /*default*/ 9, 9, 9, /*expected*/ 5, 5, 4);
- check("maxbg=4", /*default*/ 9, 9, 9, /*expected*/ 9, 4, 4);
- check("minbg=3", /*default*/ 9, 9, 9, /*expected*/ 9, 9, 3);
+ check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
+ .setInt("total", 5)
+ .setInt("maxbg", 4)
+ .setInt("minbg", 3)
+ .build(),
+ /*default*/ 9, 9, 9, /*expected*/ 5, 4, 3);
+ check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
+ .setInt("total", 5).build(),
+ /*default*/ 9, 9, 9, /*expected*/ 5, 5, 4);
+ check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
+ .setInt("maxbg", 4).build(),
+ /*default*/ 9, 9, 9, /*expected*/ 9, 4, 4);
+ check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
+ .setInt("minbg", 3).build(),
+ /*default*/ 9, 9, 9, /*expected*/ 9, 9, 3);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
index 946f27e09fdb..d36dcce800eb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
@@ -20,7 +20,7 @@ import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PackageParser
-import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.Postsubmit
import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.appInfo
import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.pkgInfo
import com.android.server.pm.parsing.pkg.AndroidPackage
@@ -38,7 +38,7 @@ import org.junit.runners.Parameterized
* This test has to be updated manually whenever the info generation behavior changes, since
* there's no single place where flag -> field is defined besides this test.
*/
-@Presubmit
+@Postsubmit
@RunWith(Parameterized::class)
class AndroidPackageInfoFlagBehaviorTest : AndroidPackageParsingTestBase() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
index f96ebda67602..574921cdbd05 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
@@ -17,26 +17,20 @@
package com.android.server.pm.parsing
import android.content.pm.PackageManager
-import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.Postsubmit
import androidx.test.filters.LargeTest
import com.google.common.truth.Expect
-
import org.junit.Rule
import org.junit.Test
-import org.junit.rules.Timeout
-import java.util.concurrent.TimeUnit
/**
* Collects APKs from the device and verifies that the new parsing behavior outputs
* the same exposed Info object as the old parsing logic.
*/
-@Presubmit
+@Postsubmit
class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
@get:Rule
- val timeout = Timeout(4, TimeUnit.MINUTES)
-
- @get:Rule
val expect = Expect.create()
@Test
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
index d5aee5d208f5..2c719ff9e8b3 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
@@ -120,17 +120,17 @@ public class UriGrantsMockContext extends ContextWrapper {
LocalServices.addService(PackageManagerInternal.class, mPmInternal);
for (int userId : new int[] { USER_PRIMARY, USER_SECONDARY }) {
- when(mPmInternal.getPackageUidInternal(eq(PKG_SOCIAL), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_SOCIAL), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_SOCIAL));
- when(mPmInternal.getPackageUidInternal(eq(PKG_CAMERA), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_CAMERA), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_CAMERA));
- when(mPmInternal.getPackageUidInternal(eq(PKG_PRIVATE), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_PRIVATE), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_PRIVATE));
- when(mPmInternal.getPackageUidInternal(eq(PKG_PUBLIC), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_PUBLIC), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_PUBLIC));
- when(mPmInternal.getPackageUidInternal(eq(PKG_FORCE), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_FORCE), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_FORCE));
- when(mPmInternal.getPackageUidInternal(eq(PKG_COMPLEX), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_COMPLEX), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_COMPLEX));
when(mPmInternal.resolveContentProvider(eq(PKG_CAMERA), anyInt(), eq(userId)))
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 f860e174fd15..59f0a7987bda 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -544,7 +544,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity = new ActivityBuilder(mAtm)
.setTask(mTask)
.setLaunchTaskBehind(true)
- .setConfigChanges(CONFIG_ORIENTATION)
+ .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)
.build();
mActivity.setState(Task.ActivityState.STOPPED, "Testing");
@@ -1190,7 +1190,7 @@ public class ActivityRecordTests extends WindowTestsBase {
assertEquals(DESTROYING, mActivity.getState());
assertTrue(mActivity.finishing);
- verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+ verify(mActivity).destroyImmediately(anyString());
}
/**
@@ -1214,7 +1214,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Verify that the activity was not actually destroyed, but waits for next one to come up
// instead.
- verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+ verify(mActivity, never()).destroyImmediately(anyString());
assertEquals(FINISHING, mActivity.getState());
assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
}
@@ -1238,7 +1238,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.completeFinishing("test");
// Verify that the activity is not destroyed immediately, but waits for next one to come up.
- verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+ verify(mActivity, never()).destroyImmediately(anyString());
assertEquals(FINISHING, mActivity.getState());
assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
}
@@ -1250,26 +1250,26 @@ public class ActivityRecordTests extends WindowTestsBase {
@Test
public void testDestroyImmediately_hadApp_finishing() {
mActivity.finishing = true;
- mActivity.destroyImmediately(false /* removeFromApp */, "test");
+ mActivity.destroyImmediately("test");
assertEquals(DESTROYING, mActivity.getState());
}
/**
* Test that the activity will be moved to destroyed state immediately if it was not marked as
- * finishing before {@link ActivityRecord#destroyImmediately(boolean, String)}.
+ * finishing before {@link ActivityRecord#destroyImmediately(String)}.
*/
@Test
public void testDestroyImmediately_hadApp_notFinishing() {
mActivity.finishing = false;
- mActivity.destroyImmediately(false /* removeFromApp */, "test");
+ mActivity.destroyImmediately("test");
assertEquals(DESTROYED, mActivity.getState());
}
/**
* Test that an activity with no process attached and that is marked as finishing will be
- * removed from task when {@link ActivityRecord#destroyImmediately(boolean, String)} is called.
+ * removed from task when {@link ActivityRecord#destroyImmediately(String)} is called.
*/
@Test
public void testDestroyImmediately_noApp_finishing() {
@@ -1277,7 +1277,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.finishing = true;
final Task task = mActivity.getTask();
- mActivity.destroyImmediately(false /* removeFromApp */, "test");
+ mActivity.destroyImmediately("test");
assertEquals(DESTROYED, mActivity.getState());
assertNull(mActivity.getTask());
@@ -1294,7 +1294,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.finishing = false;
final Task task = mActivity.getTask();
- mActivity.destroyImmediately(false /* removeFromApp */, "test");
+ mActivity.destroyImmediately("test");
assertEquals(DESTROYED, mActivity.getState());
assertEquals(task, mActivity.getTask());
@@ -1310,7 +1310,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.safelyDestroy("test");
- verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+ verify(mActivity, never()).destroyImmediately(anyString());
}
/**
@@ -1322,7 +1322,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.safelyDestroy("test");
- verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+ verify(mActivity).destroyImmediately(anyString());
}
@Test
@@ -1655,13 +1655,13 @@ public class ActivityRecordTests extends WindowTestsBase {
assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
.diff(wpc.getRequestedOverrideConfiguration()));
- secondActivity.destroyImmediately(true, "");
+ secondActivity.destroyImmediately("");
assertTrue(wpc.registeredForActivityConfigChanges());
assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
.diff(wpc.getRequestedOverrideConfiguration()));
- firstActivity.destroyImmediately(true, "");
+ firstActivity.destroyImmediately("");
assertTrue(wpc.registeredForActivityConfigChanges());
assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
@@ -1714,6 +1714,27 @@ public class ActivityRecordTests extends WindowTestsBase {
}
+ @Test
+ public void testProcessInfoUpdateWhenSetState() {
+ spyOn(mActivity.app);
+ verifyProcessInfoUpdate(RESUMED, true /* shouldUpdate */, true /* activityChange */);
+ verifyProcessInfoUpdate(PAUSED, false /* shouldUpdate */, false /* activityChange */);
+ verifyProcessInfoUpdate(STOPPED, false /* shouldUpdate */, false /* activityChange */);
+ verifyProcessInfoUpdate(STARTED, true /* shouldUpdate */, true /* activityChange */);
+
+ mActivity.app.removeActivity(mActivity, true /* keepAssociation */);
+ verifyProcessInfoUpdate(DESTROYING, true /* shouldUpdate */, false /* activityChange */);
+ verifyProcessInfoUpdate(DESTROYED, true /* shouldUpdate */, false /* activityChange */);
+ }
+
+ private void verifyProcessInfoUpdate(ActivityState state, boolean shouldUpdate,
+ boolean activityChange) {
+ reset(mActivity.app);
+ mActivity.setState(state, "test");
+ verify(mActivity.app, times(shouldUpdate ? 1 : 0)).updateProcessInfo(anyBoolean(),
+ eq(activityChange), anyBoolean(), anyBoolean());
+ }
+
/**
* Creates an activity on display. For non-default display request it will also create a new
* display with custom DisplayInfo.
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 d54b4a0a72f6..f8baf8497069 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1110,7 +1110,7 @@ public class DisplayContentTests extends WindowTestsBase {
performLayout(mDisplayContent);
// The frame is empty because the requested height is zero.
- assertTrue(win.getFrameLw().isEmpty());
+ assertTrue(win.getFrame().isEmpty());
// The window should be scheduled to resize then the client may report a new non-empty size.
win.updateResizingWindowIfNeeded();
assertThat(mWm.mResizingWindows).contains(win);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 0675c6d04422..2d834ac57f51 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -114,7 +114,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow = spy(createWindow(null, TYPE_APPLICATION, "window"));
// We only test window frames set by DisplayPolicy, so here prevents computeFrameLw from
// changing those frames.
- doNothing().when(mWindow).computeFrameLw();
+ doNothing().when(mWindow).computeFrame();
final WindowManager.LayoutParams attrs = mWindow.mAttrs;
attrs.width = MATCH_PARENT;
@@ -179,7 +179,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
WindowState win = createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, "StatusBarSubPanel");
win.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_TOP_GESTURES};
- win.getFrameLw().set(0, 0, 500, 100);
+ win.getFrame().set(0, 0, 500, 100);
addWindow(win);
InsetsStateController controller = mDisplayContent.getInsetsStateController();
@@ -207,7 +207,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.removeWindowLw(mStatusBarWindow); // Removes the existing one.
WindowState win = createWindow(null, TYPE_STATUS_BAR, "StatusBar");
win.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR};
- win.getFrameLw().set(0, 0, 500, 100);
+ win.getFrame().set(0, 0, 500, 100);
addWindow(win);
mDisplayContent.getInsetsStateController().onPostLayout();
@@ -232,7 +232,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
WindowState win1 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel1");
win1.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
win1.mAttrs.gravity = Gravity.TOP;
- win1.getFrameLw().set(0, 0, 200, 500);
+ win1.getFrame().set(0, 0, 200, 500);
addWindow(win1);
assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_TOP);
@@ -241,7 +241,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
WindowState win2 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel2");
win2.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
win2.mAttrs.gravity = Gravity.BOTTOM;
- win2.getFrameLw().set(0, 0, 200, 500);
+ win2.getFrame().set(0, 0, 200, 500);
addWindow(win2);
assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_BOTTOM);
@@ -250,7 +250,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
WindowState win3 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel3");
win3.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
win3.mAttrs.gravity = Gravity.LEFT;
- win3.getFrameLw().set(0, 0, 200, 500);
+ win3.getFrame().set(0, 0, 200, 500);
addWindow(win3);
assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_LEFT);
@@ -259,7 +259,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
WindowState win4 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel4");
win4.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
win4.mAttrs.gravity = Gravity.RIGHT;
- win4.getFrameLw().set(0, 0, 200, 500);
+ win4.getFrame().set(0, 0, 200, 500);
addWindow(win4);
assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_RIGHT);
@@ -274,11 +274,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
@@ -290,11 +290,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
@@ -306,11 +306,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
@@ -322,11 +322,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
@@ -342,11 +342,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
@@ -362,11 +362,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
@@ -381,11 +381,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0);
assertInsetByTopBottom(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
@@ -402,10 +402,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
}
@Test
@@ -422,10 +422,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
}
@Test
@@ -442,10 +442,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
- assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+ assertInsetBy(mWindow.getContentFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
}
@Test
@@ -462,10 +462,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
- assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+ assertInsetBy(mWindow.getContentFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
}
@Test
@@ -484,10 +484,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
}
@Test
@@ -506,10 +506,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
}
@Test
@@ -529,10 +529,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
}
@@ -549,11 +549,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
- assertInsetBy(mWindow.getContentFrameLw(),
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mWindow.getContentFrame(),
DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
}
@Test
@@ -570,11 +570,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
- assertInsetBy(mWindow.getStableFrameLw(), NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
- assertInsetBy(mWindow.getContentFrameLw(),
+ assertInsetBy(mWindow.getStableFrame(), NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
+ assertInsetBy(mWindow.getContentFrame(),
NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
}
@Test
@@ -594,8 +594,8 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
- assertInsetBy(mWindow.getContentFrameLw(),
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mWindow.getContentFrame(),
DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
}
@@ -615,7 +615,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
}
@Test
@@ -636,8 +636,8 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
- assertInsetBy(mWindow.getContentFrameLw(),
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mWindow.getContentFrame(),
DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
}
@@ -655,11 +655,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
- assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+ assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
NAV_BAR_HEIGHT);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
}
@Test
@@ -676,12 +676,12 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0,
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0,
NAV_BAR_HEIGHT);
- assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
+ assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
NAV_BAR_HEIGHT);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
}
@Test
@@ -698,11 +698,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
- assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+ assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
NAV_BAR_HEIGHT);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
}
@Test
@@ -719,11 +719,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
- assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+ assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
NAV_BAR_HEIGHT);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
}
@Test
@@ -740,11 +740,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
}
@Test
@@ -904,34 +904,34 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, TOP);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), DECOR_WINDOW_INSET, NAV_BAR_HEIGHT);
// Decor on bottom
updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, BOTTOM);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT,
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT,
DECOR_WINDOW_INSET);
// Decor on the left
updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, LEFT);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetBy(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, STATUS_BAR_HEIGHT, 0,
+ assertInsetBy(mWindow.getContentFrame(), DECOR_WINDOW_INSET, STATUS_BAR_HEIGHT, 0,
NAV_BAR_HEIGHT);
// Decor on the right
updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, RIGHT);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, DECOR_WINDOW_INSET,
+ assertInsetBy(mWindow.getContentFrame(), 0, STATUS_BAR_HEIGHT, DECOR_WINDOW_INSET,
NAV_BAR_HEIGHT);
// Decor not allowed as inset
updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, DECOR_WINDOW_INSET, TOP);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
}
private void updateDecorWindow(WindowState decorWindow, int width, int height, int gravity) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 4483f8c341cf..b50530ed3059 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -297,7 +297,7 @@ public class DisplayPolicyTests extends WindowTestsBase {
final WindowState navigationBar = createNavigationBarWindow();
- navigationBar.getFrameLw().set(new Rect(100, 200, 200, 300));
+ navigationBar.getFrame().set(new Rect(100, 200, 200, 300));
assertFalse("Freeform is overlapping with navigation bar",
DisplayPolicy.isOverlappingWithNavBar(targetWin, navigationBar));
@@ -377,7 +377,7 @@ public class DisplayPolicyTests extends WindowTestsBase {
mDisplayContent.setInputMethodWindowLocked(mImeWindow);
mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM);
- mImeWindow.getGivenContentInsetsLw().set(0, displayInfo.logicalHeight, 0, 0);
+ mImeWindow.mGivenContentInsets.set(0, displayInfo.logicalHeight, 0, 0);
mImeWindow.getControllableInsetProvider().setServerVisible(true);
displayPolicy.beginLayoutLw(mDisplayContent.mDisplayFrames, 0 /* UI mode */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index 555906d4c910..608305c33168 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -43,7 +43,6 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
import android.platform.test.annotations.Presubmit;
-import android.util.IntArray;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.test.InsetsModeSession;
@@ -242,8 +241,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
}).when(policy).startAnimation(anyBoolean(), any(), any());
policy.updateBarControlTarget(mAppWindow);
- policy.showTransient(
- IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+ policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
waitUntilWindowAnimatorIdle();
final InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
@@ -271,8 +269,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
doNothing().when(policy).startAnimation(anyBoolean(), any(), any());
policy.updateBarControlTarget(mAppWindow);
- policy.showTransient(
- IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+ policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
waitUntilWindowAnimatorIdle();
final InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
@@ -301,8 +298,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
doNothing().when(policy).startAnimation(anyBoolean(), any(), any());
policy.updateBarControlTarget(mAppWindow);
- policy.showTransient(
- IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+ policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
waitUntilWindowAnimatorIdle();
InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
@@ -340,8 +336,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
doNothing().when(policy).startAnimation(anyBoolean(), any(), any());
policy.updateBarControlTarget(app);
- policy.showTransient(
- IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+ policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
final InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(app);
policy.updateBarControlTarget(app2);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index 1d6dd0b566a1..a0fa9369e7a8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -61,7 +61,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
@Test
public void testPostLayout() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
statusBar.mHasSurface = true;
mProvider.setWindow(statusBar, null, null);
mProvider.onPostLayout();
@@ -76,9 +76,9 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
@Test
public void testPostLayout_givenInsets() {
final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
- ime.getFrameLw().set(0, 0, 500, 100);
- ime.getGivenContentInsetsLw().set(0, 0, 0, 60);
- ime.getGivenVisibleInsetsLw().set(0, 0, 0, 75);
+ ime.getFrame().set(0, 0, 500, 100);
+ ime.mGivenContentInsets.set(0, 0, 0, 60);
+ ime.mGivenVisibleInsets.set(0, 0, 0, 75);
ime.mHasSurface = true;
mProvider.setWindow(ime, null, null);
mProvider.onPostLayout();
@@ -94,7 +94,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
@Test
public void testPostLayout_invisible() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null, null);
mProvider.onPostLayout();
assertEquals(Insets.NONE, mProvider.getSource().calculateInsets(new Rect(0, 0, 500, 500),
@@ -104,7 +104,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
@Test
public void testPostLayout_frameProvider() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
statusBar.mHasSurface = true;
mProvider.setWindow(statusBar,
(displayFrames, windowState, rect) -> {
@@ -118,7 +118,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
public void testUpdateControlForTarget() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
// We must not have control or control target before we have the insets source window.
mProvider.updateControlForTarget(target, true /* force */);
@@ -163,7 +163,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
public void testUpdateControlForFakeTarget() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null, null);
mProvider.updateControlForFakeTarget(target);
assertNotNull(mProvider.getControl(target));
@@ -176,7 +176,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
public void testUpdateSourceFrameForIme() {
final WindowState inputMethod = createWindow(null, TYPE_INPUT_METHOD, "inputMethod");
- inputMethod.getFrameLw().set(new Rect(0, 400, 500, 500));
+ inputMethod.getFrame().set(new Rect(0, 400, 500, 500));
mImeProvider.setWindow(inputMethod, null, null);
mImeProvider.setServerVisible(false);
@@ -190,7 +190,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
mImeProvider.setServerVisible(true);
mImeSource.setVisible(true);
mImeProvider.updateSourceFrame();
- assertEquals(inputMethod.getFrameLw(), mImeSource.getFrame());
+ assertEquals(inputMethod.getFrame(), mImeSource.getFrame());
insets = mImeSource.calculateInsets(new Rect(0, 0, 500, 500),
false /* ignoreVisibility */);
assertEquals(Insets.of(0, 0, 0, 100), insets);
@@ -200,7 +200,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
public void testInsetsModified() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null, null);
mProvider.updateControlForTarget(target, false /* force */);
InsetsState state = new InsetsState();
@@ -213,7 +213,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
public void testInsetsModified_noControl() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null, null);
InsetsState state = new InsetsState();
state.getSource(ITYPE_STATUS_BAR).setVisible(false);
@@ -224,7 +224,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
@Test
public void testInsetGeometries() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
statusBar.mHasSurface = true;
mProvider.setWindow(statusBar, null, null);
mProvider.onPostLayout();
@@ -236,7 +236,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
false /* ignoreVisibility */));
// Don't apply left insets if window is left-of inset-window but still overlaps
- statusBar.getFrameLw().set(100, 0, 0, 0);
+ statusBar.getFrame().set(100, 0, 0, 0);
assertEquals(Insets.of(0, 0, 0, 0),
mProvider.getSource().calculateInsets(new Rect(-100, 0, 400, 500),
false /* ignoreVisibility */));
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 085230d35c6a..59f8cc8c3412 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -346,8 +346,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
assertTrue(rotatedState.getSource(ITYPE_STATUS_BAR).isVisible());
provider.getSource().setVisible(false);
- mDisplayContent.getInsetsPolicy().showTransient(
- IntArray.wrap(new int[] { ITYPE_STATUS_BAR }));
+ mDisplayContent.getInsetsPolicy().showTransient(new int[] { ITYPE_STATUS_BAR });
assertTrue(mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR));
assertFalse(app.getInsetsState().getSource(ITYPE_STATUS_BAR).isVisible());
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 72899e726b6e..191c33c61aca 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -184,7 +184,7 @@ public class RootWindowContainerTests extends WindowTestsBase {
};
activities[0].detachFromProcess();
activities[1].finishing = true;
- activities[1].destroyImmediately(true /* removeFromApp */, "test");
+ activities[1].destroyImmediately("test");
spyOn(wpc);
doReturn(true).when(wpc).isRemoved();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index fc54e1de888f..08537a4ea9c1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -50,6 +50,7 @@ import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -245,17 +246,17 @@ public class TaskRecordTests extends WindowTestsBase {
final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
final DisplayContent display = new TestDisplayContent.Builder(mAtm,
fullScreenBounds.width(), fullScreenBounds.height()).setCanRotate(false).build();
- assertTrue(mRootWindowContainer.getDisplayContent(display.mDisplayId) != null);
+ assertNotNull(mRootWindowContainer.getDisplayContent(display.mDisplayId));
// Fix the display orientation to landscape which is the natural rotation (0) for the test
// display.
final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
- Task stack = new StackBuilder(mRootWindowContainer)
+ final Task stack = new StackBuilder(mRootWindowContainer)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
- Task task = stack.getBottomMostTask();
- ActivityRecord root = task.getTopNonFinishingActivity();
+ final Task task = stack.getBottomMostTask();
+ final ActivityRecord root = task.getTopNonFinishingActivity();
assertEquals(fullScreenBounds, task.getBounds());
@@ -267,7 +268,7 @@ public class TaskRecordTests extends WindowTestsBase {
assertEquals(fullScreenBounds.height(), task.getBounds().height());
// Top activity gets used
- ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).setStack(stack).build();
+ final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).setStack(stack).build();
assertEquals(top, task.getTopNonFinishingActivity());
top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
@@ -304,6 +305,33 @@ public class TaskRecordTests extends WindowTestsBase {
}
@Test
+ public void testReportsOrientationRequestInLetterboxForOrientation() {
+ final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
+ final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm,
+ fullScreenBounds.width(), fullScreenBounds.height()).setCanRotate(false).build();
+ assertNotNull(mRootWindowContainer.getDisplayContent(display.mDisplayId));
+ // Fix the display orientation to landscape which is the natural rotation (0) for the test
+ // display.
+ final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
+ dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
+ dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
+
+ final Task stack = new StackBuilder(mRootWindowContainer)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
+ final Task task = stack.getBottomMostTask();
+ ActivityRecord root = task.getTopNonFinishingActivity();
+
+ assertEquals(fullScreenBounds, task.getBounds());
+
+ // Setting app to fixed portrait fits within parent
+ root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+ assertThat(task.getBounds().width()).isLessThan(task.getBounds().height());
+
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getOrientation());
+ }
+
+ @Test
public void testIgnoresForcedOrientationWhenParentHandles() {
final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
DisplayContent display = new TestDisplayContent.Builder(
@@ -404,6 +432,31 @@ public class TaskRecordTests extends WindowTestsBase {
}
@Test
+ public void testComputeConfigResourceLayoutOverrides() {
+ final Rect fullScreenBounds = new Rect(0, 0, 1000, 2500);
+ TestDisplayContent display = new TestDisplayContent.Builder(
+ mAtm, fullScreenBounds.width(), fullScreenBounds.height()).build();
+ final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build();
+ final Configuration inOutConfig = new Configuration();
+ final Configuration parentConfig = new Configuration();
+ final Rect nonLongBounds = new Rect(0, 0, 1000, 1250);
+ parentConfig.windowConfiguration.setBounds(fullScreenBounds);
+ parentConfig.windowConfiguration.setAppBounds(fullScreenBounds);
+ parentConfig.densityDpi = 400;
+ parentConfig.screenHeightDp = (fullScreenBounds.bottom * 160) / parentConfig.densityDpi;
+ parentConfig.screenWidthDp = (fullScreenBounds.right * 160) / parentConfig.densityDpi;
+ parentConfig.windowConfiguration.setRotation(ROTATION_0);
+
+ // Set BOTH screenW/H to an override value
+ inOutConfig.screenWidthDp = nonLongBounds.width() * 160 / parentConfig.densityDpi;
+ inOutConfig.screenHeightDp = nonLongBounds.height() * 160 / parentConfig.densityDpi;
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig);
+
+ // screenLayout should honor override when both screenW/H are set.
+ assertTrue((inOutConfig.screenLayout & Configuration.SCREENLAYOUT_LONG_NO) != 0);
+ }
+
+ @Test
public void testComputeNestedConfigResourceOverrides() {
final Task task = new TaskBuilder(mSupervisor).build();
assertTrue(task.getResolvedOverrideBounds().isEmpty());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 4a8e8dafb57d..dc859046db42 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -86,11 +86,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public int getMaxWallpaperLayer() {
- return 0;
- }
-
- @Override
public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
return attrs.type == TYPE_NOTIFICATION_SHADE;
}
@@ -377,11 +372,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public boolean isTopLevelWindow(int windowType) {
- return false;
- }
-
- @Override
public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index 6ed762283524..78dfd407ff4e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -55,6 +55,18 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase {
}
@Test
+ public void testSkipResume() {
+ final ActivityRecord activity = createTestActivityRecord(mDisplayContent);
+ activity.mLaunchTaskBehind = true;
+ mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity);
+ mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(activity);
+
+ // Make sure our handler processed the message.
+ waitHandlerIdle(mWm.mH);
+ assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
+ }
+
+ @Test
public void testMultiple() {
final ActivityRecord activity1 = createTestActivityRecord(mDisplayContent);
final ActivityRecord activity2 = createTestActivityRecord(mDisplayContent);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index ed9e2707ae39..63367ac2badf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -133,8 +133,8 @@ public class WallpaperControllerTests extends WindowTestsBase {
int expectedWidth = (int) (wallpaperWidth * (displayHeight / (double) wallpaperHeight));
// Check that the wallpaper is correctly scaled
- assertEquals(new Rect(0, 0, expectedWidth, displayHeight), wallpaperWindow.getFrameLw());
- Rect portraitFrame = wallpaperWindow.getFrameLw();
+ assertEquals(new Rect(0, 0, expectedWidth, displayHeight), wallpaperWindow.getFrame());
+ Rect portraitFrame = wallpaperWindow.getFrame();
// Rotate the display
dc.getDisplayRotation().updateOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, true);
@@ -149,7 +149,7 @@ public class WallpaperControllerTests extends WindowTestsBase {
// Check that the wallpaper has the same frame in landscape than in portrait
assertEquals(Configuration.ORIENTATION_LANDSCAPE, dc.getConfiguration().orientation);
- assertEquals(portraitFrame, wallpaperWindow.getFrameLw());
+ assertEquals(portraitFrame, wallpaperWindow.getFrame());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index eb2aa41192c2..ca3626d09062 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -89,29 +89,29 @@ public class WindowFrameTests extends WindowTestsBase {
}
private void assertFrame(WindowState w, Rect frame) {
- assertEquals(w.getFrameLw(), frame);
+ assertEquals(w.getFrame(), frame);
}
private void assertFrame(WindowState w, int left, int top, int right, int bottom) {
- assertRect(w.getFrameLw(), left, top, right, bottom);
+ assertRect(w.getFrame(), left, top, right, bottom);
}
private void assertRelFrame(WindowState w, int left, int top, int right, int bottom) {
- assertRect(w.getRelativeFrameLw(), left, top, right, bottom);
+ assertRect(w.getRelativeFrame(), left, top, right, bottom);
}
private void assertContentFrame(WindowState w, Rect expectedRect) {
- assertRect(w.getContentFrameLw(), expectedRect.left, expectedRect.top, expectedRect.right,
+ assertRect(w.getContentFrame(), expectedRect.left, expectedRect.top, expectedRect.right,
expectedRect.bottom);
}
private void assertVisibleFrame(WindowState w, Rect expectedRect) {
- assertRect(w.getVisibleFrameLw(), expectedRect.left, expectedRect.top, expectedRect.right,
+ assertRect(w.getVisibleFrame(), expectedRect.left, expectedRect.top, expectedRect.right,
expectedRect.bottom);
}
private void assertStableFrame(WindowState w, Rect expectedRect) {
- assertRect(w.getStableFrameLw(), expectedRect.left, expectedRect.top, expectedRect.right,
+ assertRect(w.getStableFrame(), expectedRect.left, expectedRect.top, expectedRect.right,
expectedRect.bottom);
}
@@ -155,7 +155,7 @@ public class WindowFrameTests extends WindowTestsBase {
// the difference between mFrame and ContentFrame. Visible
// and stable frames work the same way.
w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf);
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 0, 0, 1000, 1000);
assertRelFrame(w, 0, 0, 1000, 1000);
assertContentInset(w, 0, topContentInset, 0, bottomContentInset);
@@ -170,14 +170,14 @@ public class WindowFrameTests extends WindowTestsBase {
w.mAttrs.width = 100; w.mAttrs.height = 100; //have to clear MATCH_PARENT
w.mRequestedWidth = 100;
w.mRequestedHeight = 100;
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 100, 100, 200, 200);
assertRelFrame(w, 100, 100, 200, 200);
assertContentInset(w, 0, 0, 0, 0);
// In this case the frames are shrunk to the window frame.
- assertContentFrame(w, w.getFrameLw());
- assertVisibleFrame(w, w.getFrameLw());
- assertStableFrame(w, w.getFrameLw());
+ assertContentFrame(w, w.getFrame());
+ assertVisibleFrame(w, w.getFrame());
+ assertStableFrame(w, w.getFrame());
}
@Test
@@ -193,7 +193,7 @@ public class WindowFrameTests extends WindowTestsBase {
// Here the window has FILL_PARENT, FILL_PARENT
// so we expect it to fill the entire available frame.
w.getWindowFrames().setFrames(pf, pf, pf, pf, pf, pf);
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 0, 0, 1000, 1000);
assertRelFrame(w, 0, 0, 1000, 1000);
@@ -202,14 +202,14 @@ public class WindowFrameTests extends WindowTestsBase {
// and we use mRequestedWidth/mRequestedHeight
w.mAttrs.width = 300;
w.mAttrs.height = 300;
- w.computeFrameLw();
+ w.computeFrame();
// Explicit width and height without requested width/height
// gets us nothing.
assertFrame(w, 0, 0, 0, 0);
w.mRequestedWidth = 300;
w.mRequestedHeight = 300;
- w.computeFrameLw();
+ w.computeFrame();
// With requestedWidth/Height we can freely choose our size within the
// parent bounds.
assertFrame(w, 0, 0, 300, 300);
@@ -222,14 +222,14 @@ public class WindowFrameTests extends WindowTestsBase {
w.mRequestedWidth = -1;
w.mAttrs.width = 100;
w.mAttrs.height = 100;
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 0, 0, 100, 100);
w.mAttrs.flags = 0;
// But sizes too large will be clipped to the containing frame
w.mRequestedWidth = 1200;
w.mRequestedHeight = 1200;
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 0, 0, 1000, 1000);
// Before they are clipped though windows will be shifted
@@ -237,7 +237,7 @@ public class WindowFrameTests extends WindowTestsBase {
w.mAttrs.y = 300;
w.mRequestedWidth = 1000;
w.mRequestedHeight = 1000;
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 0, 0, 1000, 1000);
// If there is room to move around in the parent frame the window will be shifted according
@@ -247,18 +247,18 @@ public class WindowFrameTests extends WindowTestsBase {
w.mRequestedWidth = 300;
w.mRequestedHeight = 300;
w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP;
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 700, 0, 1000, 300);
assertRelFrame(w, 700, 0, 1000, 300);
w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM;
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 700, 700, 1000, 1000);
assertRelFrame(w, 700, 700, 1000, 1000);
// Window specified x and y are interpreted as offsets in the opposite
// direction of gravity
w.mAttrs.x = 100;
w.mAttrs.y = 100;
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 600, 600, 900, 900);
assertRelFrame(w, 600, 600, 900, 900);
}
@@ -285,12 +285,12 @@ public class WindowFrameTests extends WindowTestsBase {
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
final WindowFrames windowFrames = w.getWindowFrames();
windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
- w.computeFrameLw();
+ w.computeFrame();
// For non fullscreen tasks the containing frame is based off the
// task bounds not the parent frame.
- assertEquals(resolvedTaskBounds, w.getFrameLw());
- assertEquals(0, w.getRelativeFrameLw().left);
- assertEquals(0, w.getRelativeFrameLw().top);
+ assertEquals(resolvedTaskBounds, w.getFrame());
+ assertEquals(0, w.getRelativeFrame().left);
+ assertEquals(0, w.getRelativeFrame().top);
assertContentFrame(w, resolvedTaskBounds);
assertContentInset(w, 0, 0, 0, 0);
@@ -300,10 +300,10 @@ public class WindowFrameTests extends WindowTestsBase {
final int cfBottom = logicalHeight / 2;
final Rect cf = new Rect(0, 0, cfRight, cfBottom);
windowFrames.setFrames(pf, pf, cf, cf, pf, cf);
- w.computeFrameLw();
- assertEquals(resolvedTaskBounds, w.getFrameLw());
- assertEquals(0, w.getRelativeFrameLw().left);
- assertEquals(0, w.getRelativeFrameLw().top);
+ w.computeFrame();
+ assertEquals(resolvedTaskBounds, w.getFrame());
+ assertEquals(0, w.getRelativeFrame().left);
+ assertEquals(0, w.getRelativeFrame().top);
int contentInsetRight = resolvedTaskBounds.right - cfRight;
int contentInsetBottom = resolvedTaskBounds.bottom - cfBottom;
assertContentInset(w, 0, 0, contentInsetRight, contentInsetBottom);
@@ -334,12 +334,12 @@ public class WindowFrameTests extends WindowTestsBase {
final WindowFrames windowFrames = w.getWindowFrames();
windowFrames.setFrames(pf, df, cf, vf, dcf, sf);
- w.computeFrameLw();
+ w.computeFrame();
assertPolicyCrop(w, 0, cf.top, logicalWidth, cf.bottom);
windowFrames.mDecorFrame.setEmpty();
// Likewise with no decor frame we would get no crop
- w.computeFrameLw();
+ w.computeFrame();
assertPolicyCrop(w, 0, 0, logicalWidth, logicalHeight);
// Now we set up a window which doesn't fill the entire decor frame.
@@ -353,7 +353,7 @@ public class WindowFrameTests extends WindowTestsBase {
w.mAttrs.height = logicalHeight / 2;
w.mRequestedWidth = logicalWidth / 2;
w.mRequestedHeight = logicalHeight / 2;
- w.computeFrameLw();
+ w.computeFrame();
// Normally the crop is shrunk from the decor frame
// to the computed window frame.
@@ -390,7 +390,7 @@ public class WindowFrameTests extends WindowTestsBase {
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
final WindowFrames windowFrames = w.getWindowFrames();
windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
- w.computeFrameLw();
+ w.computeFrame();
// For non fullscreen tasks the containing frame is based off the
// task bounds not the parent frame.
assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
@@ -408,7 +408,7 @@ public class WindowFrameTests extends WindowTestsBase {
task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
task.setBounds(null);
windowFrames.setFrames(pf, pf, cf, cf, pf, cf);
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, cf);
assertContentFrame(w, cf);
assertContentInset(w, 0, 0, 0, 0);
@@ -430,7 +430,7 @@ public class WindowFrameTests extends WindowTestsBase {
final WindowFrames windowFrames = w.getWindowFrames();
windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
windowFrames.setDisplayCutout(cutout);
- w.computeFrameLw();
+ w.computeFrame();
assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetTop(), 50);
assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetBottom(), 0);
@@ -469,20 +469,20 @@ public class WindowFrameTests extends WindowTestsBase {
task.setBounds(winRect);
w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf);
- w.computeFrameLw();
+ w.computeFrame();
final Rect expected = new Rect(winRect.left, cf.bottom - winRect.height(),
winRect.right, cf.bottom);
- assertEquals(expected, w.getFrameLw());
- assertEquals(expected, w.getContentFrameLw());
- assertEquals(expected, w.getVisibleFrameLw());
+ assertEquals(expected, w.getFrame());
+ assertEquals(expected, w.getContentFrame());
+ assertEquals(expected, w.getVisibleFrame());
// Now check that it won't get moved beyond the top and then has appropriate insets
winRect.bottom = 600;
task.setBounds(winRect);
w.setBounds(winRect);
w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf);
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, winRect.left, 0, winRect.right, winRect.height());
expected.top = 0;
@@ -492,8 +492,8 @@ public class WindowFrameTests extends WindowTestsBase {
// Check that it's moved back without ime insets
w.getWindowFrames().setFrames(pf, df, pf, pf, dcf, sf);
- w.computeFrameLw();
- assertEquals(winRect, w.getFrameLw());
+ w.computeFrame();
+ assertEquals(winRect, w.getFrame());
}
private WindowState createWindow() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 91352972e772..289d54e967f5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -88,20 +88,14 @@ import java.util.List;
@Presubmit
@RunWith(WindowTestRunner.class)
public class WindowOrganizerTests extends WindowTestsBase {
- private ITaskOrganizer registerMockOrganizer(int windowingMode) {
+ private ITaskOrganizer registerMockOrganizer() {
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
when(organizer.asBinder()).thenReturn(new Binder());
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(
- organizer, windowingMode);
-
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(organizer);
return organizer;
}
- private ITaskOrganizer registerMockOrganizer() {
- return registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
- }
-
Task createTask(Task stack, boolean fakeDraw) {
final Task task = createTaskInStack(stack, 0);
@@ -133,11 +127,12 @@ public class WindowOrganizerTests extends WindowTestsBase {
final Task task = createTask(stack);
final ITaskOrganizer organizer = registerMockOrganizer();
- task.setTaskOrganizer(organizer);
+ stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ stack.setTaskOrganizer(organizer);
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- task.removeImmediately();
+ stack.removeImmediately();
verify(organizer).onTaskVanished(any());
}
@@ -147,16 +142,17 @@ public class WindowOrganizerTests extends WindowTestsBase {
final Task task = createTask(stack, false);
final ITaskOrganizer organizer = registerMockOrganizer();
- task.setTaskOrganizer(organizer);
+ stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ stack.setTaskOrganizer(organizer);
verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- task.setHasBeenVisible(true);
+ stack.setHasBeenVisible(true);
assertTrue(stack.getHasBeenVisible());
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- task.removeImmediately();
+ stack.removeImmediately();
verify(organizer).onTaskVanished(any());
}
@@ -169,42 +165,14 @@ public class WindowOrganizerTests extends WindowTestsBase {
// In this test we skip making the Task visible, and verify
// that even though a TaskOrganizer is set remove doesn't emit
// a vanish callback, because we never emitted appear.
- task.setTaskOrganizer(organizer);
+ stack.setTaskOrganizer(organizer);
verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- task.removeImmediately();
+ stack.removeImmediately();
verify(organizer, never()).onTaskVanished(any());
}
@Test
- public void testSwapOrganizer() throws RemoteException {
- final Task stack = createStack();
- final Task task = createTask(stack);
- final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
- final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
-
- task.setTaskOrganizer(organizer);
- verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- task.setTaskOrganizer(organizer2);
- verify(organizer).onTaskVanished(any());
- verify(organizer2).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- }
-
- @Test
- public void testSwapWindowingModes() throws RemoteException {
- final Task stack = createStack();
- final Task task = createTask(stack);
- final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
- final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
-
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- stack.setWindowingMode(WINDOWING_MODE_PINNED);
- verify(organizer).onTaskVanished(any());
- verify(organizer2).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- }
-
- @Test
public void testTaskNoDraw() throws RemoteException {
final Task stack = createStack();
final Task task = createTask(stack, false /* fakeDraw */);
@@ -226,6 +194,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
final Task task = createTask(stack);
final ITaskOrganizer organizer = registerMockOrganizer();
+ stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
stack.setTaskOrganizer(organizer);
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTrue(stack.isOrganized());
@@ -258,7 +227,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
final Task task2 = createTask(stack2);
final Task stack3 = createStack();
final Task task3 = createTask(stack3);
- final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
+ final ITaskOrganizer organizer = registerMockOrganizer();
// First organizer is registered, verify a task appears when changing windowing mode
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
@@ -268,7 +237,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
// Now we replace the registration and1 verify the new organizer receives tasks
// newly entering the windowing mode.
- final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
+ final ITaskOrganizer organizer2 = registerMockOrganizer();
stack2.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
// One each for task and task2
verify(organizer2, times(2))
@@ -294,7 +263,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testRegisterTaskOrganizerStackWindowingModeChanges() throws RemoteException {
- final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_PINNED);
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
@@ -313,7 +282,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
final Task task = createTask(stack);
stack.setWindowingMode(WINDOWING_MODE_PINNED);
- final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_PINNED);
+ final ITaskOrganizer organizer = registerMockOrganizer();
verify(organizer, times(1))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
}
@@ -483,8 +452,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
}
};
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener);
RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
@@ -542,8 +510,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
}
};
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener);
RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
lastReportedTiles.clear();
@@ -604,10 +571,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
}
};
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(
- listener, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(
- listener, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener);
RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
RunningTaskInfo info2 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
@@ -874,7 +838,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testEnterPipParams() {
final StubOrganizer o = new StubOrganizer();
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o, WINDOWING_MODE_PINNED);
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o);
final ActivityRecord record = makePipableActivity();
final PictureInPictureParams p = new PictureInPictureParams.Builder()
@@ -895,7 +859,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
}
}
ChangeSavingOrganizer o = new ChangeSavingOrganizer();
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o, WINDOWING_MODE_PINNED);
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o);
final ActivityRecord record = makePipableActivity();
final PictureInPictureParams p = new PictureInPictureParams.Builder()
@@ -926,8 +890,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
}
}
ChangeSavingOrganizer o = new ChangeSavingOrganizer();
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o,
- WINDOWING_MODE_MULTI_WINDOW);
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o);
final Task stack = createStack();
final Task task = createTask(stack);
@@ -942,22 +905,23 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testPreventDuplicateAppear() throws RemoteException {
final Task stack = createStack();
- final Task task = createTask(stack);
+ final Task task = createTask(stack, false /* fakeDraw */);
final ITaskOrganizer organizer = registerMockOrganizer();
- task.setTaskOrganizer(organizer);
+ stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ stack.setTaskOrganizer(organizer);
// setHasBeenVisible was already called once by the set-up code.
- task.setHasBeenVisible(true);
+ stack.setHasBeenVisible(true);
verify(organizer, times(1))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- task.setTaskOrganizer(null);
+ stack.setTaskOrganizer(null);
verify(organizer, times(1)).onTaskVanished(any());
- task.setTaskOrganizer(organizer);
+ stack.setTaskOrganizer(organizer);
verify(organizer, times(2))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- task.removeImmediately();
+ stack.removeImmediately();
verify(organizer, times(2)).onTaskVanished(any());
}
@@ -966,7 +930,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
final Task stack = createStack();
final Task task = createTask(stack);
final ActivityRecord activity = createActivityRecordInTask(stack.mDisplayContent, task);
- final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
+ final ITaskOrganizer organizer = registerMockOrganizer();
// Setup the task to be controlled by the MW mode organizer
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
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 f095fd42900b..9603d28c286b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -479,7 +479,7 @@ public class WindowStateTests extends WindowTestsBase {
app.mHasSurface = true;
app.mSurfaceControl = mock(SurfaceControl.class);
try {
- app.getFrameLw().set(10, 20, 60, 80);
+ app.getFrame().set(10, 20, 60, 80);
app.updateSurfacePosition(t);
app.seamlesslyRotateIfAllowed(t, ROTATION_0, ROTATION_90, true);
@@ -519,7 +519,7 @@ public class WindowStateTests extends WindowTestsBase {
new Rect(95, 378, 105, 400));
wf.setDisplayCutout(new WmDisplayCutout(cutout, new Size(200, 400)));
- app.computeFrameLw();
+ app.computeFrame();
assertThat(app.getWmDisplayCutout().getDisplayCutout(), is(cutout.inset(7, 10, 5, 20)));
}
@@ -633,7 +633,7 @@ public class WindowStateTests extends WindowTestsBase {
final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
final DisplayContent dc = createNewDisplay();
- win0.getFrameLw().offsetTo(PARENT_WINDOW_OFFSET, 0);
+ win0.getFrame().offsetTo(PARENT_WINDOW_OFFSET, 0);
dc.reparentDisplayContent(win0, win0.getSurfaceControl());
dc.updateLocation(win0, DISPLAY_IN_PARENT_WINDOW_OFFSET, 0);
@@ -644,7 +644,7 @@ public class WindowStateTests extends WindowTestsBase {
win1.mHasSurface = true;
win1.mSurfaceControl = mock(SurfaceControl.class);
win1.mAttrs.surfaceInsets.set(1, 2, 3, 4);
- win1.getFrameLw().offsetTo(WINDOW_OFFSET, 0);
+ win1.getFrame().offsetTo(WINDOW_OFFSET, 0);
win1.updateSurfacePosition(t);
win1.getTransformationMatrix(values, matrix);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 5ce61b4e4916..38c4e0a7de02 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -1031,10 +1031,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
TestSplitOrganizer(ActivityTaskManagerService service, int displayId) {
mService = service;
mDisplayId = displayId;
- mService.mTaskOrganizerController.registerTaskOrganizer(this,
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- mService.mTaskOrganizerController.registerTaskOrganizer(this,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ mService.mTaskOrganizerController.registerTaskOrganizer(this);
WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask(
displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token;
mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask();
@@ -1134,7 +1131,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
}
@Override
- public boolean isGoneForLayoutLw() {
+ public boolean isGoneForLayout() {
return false;
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 1e5d92b270d2..81aad972898e 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1653,8 +1653,8 @@ public class UsageStatsService extends SystemService implements
// If the calling app is asking about itself, continue, else check for permission.
if (packageName.equals(callingPackage)) {
- final int actualCallingUid = mPackageManagerInternal.getPackageUidInternal(
- callingPackage, 0, userId);
+ final int actualCallingUid = mPackageManagerInternal.getPackageUid(
+ callingPackage, /* flags= */ 0, userId);
if (actualCallingUid != callingUid) {
return false;
}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
index 8f1d0addbcd8..3104c7e7e0a1 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
@@ -123,7 +123,7 @@ public class IorapForwardingService extends SystemService {
try {
iorap = IIorap.Stub.asInterface(ServiceManager.getServiceOrThrow("iorapd"));
} catch (ServiceManager.ServiceNotFoundException e) {
- handleRemoteError(e);
+ Log.w(TAG, e.getMessage());
return null;
}
diff --git a/telephony/api/system-current.txt b/telephony/api/system-current.txt
index 52e0953813a0..944edd542e40 100644
--- a/telephony/api/system-current.txt
+++ b/telephony/api/system-current.txt
@@ -687,10 +687,8 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataConnectionAllowed();
method public boolean isDataConnectivityPossible();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledWithReason(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean isIccLockEnabled();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
@@ -722,7 +720,6 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledWithReason(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean);
@@ -760,10 +757,6 @@ package android.telephony {
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
- field public static final int DATA_ENABLED_REASON_CARRIER = 2; // 0x2
- field public static final int DATA_ENABLED_REASON_POLICY = 1; // 0x1
- field public static final int DATA_ENABLED_REASON_THERMAL = 3; // 0x3
- field public static final int DATA_ENABLED_REASON_USER = 0; // 0x0
field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION";
field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID";
field public static final String EXTRA_PHONE_IN_ECM_STATE = "android.telephony.extra.PHONE_IN_ECM_STATE";
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index fa229fb47423..a229efbe9970 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4406,7 +4406,7 @@ public class CarrierConfigManager {
});
sDefaults.putBoolean(KEY_SUPPORT_WPS_OVER_IMS_BOOL, true);
sDefaults.putAll(Ims.getDefaults());
- sDefaults.putStringArray(KEY_CARRIER_CERTIFICATE_STRING_ARRAY, null);
+ sDefaults.putStringArray(KEY_CARRIER_CERTIFICATE_STRING_ARRAY, new String[0]);
sDefaults.putBoolean(KEY_FORMAT_INCOMING_NUMBER_TO_NATIONAL_FOR_JP_BOOL, false);
sDefaults.putIntArray(KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY,
new int[] {4 /* BUSY */});
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index 06c34dcf290a..905f90800305 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -50,6 +50,18 @@ public final class CellIdentityNr extends CellIdentity {
// a list of additional PLMN-IDs reported for this cell
private final ArraySet<String> mAdditionalPlmns;
+ /** @hide */
+ public CellIdentityNr() {
+ super(TAG, CellInfo.TYPE_NR, null, null, null, null);
+ mNrArfcn = CellInfo.UNAVAILABLE;
+ mPci = CellInfo.UNAVAILABLE;
+ mTac = CellInfo.UNAVAILABLE;
+ mNci = CellInfo.UNAVAILABLE;
+ mBands = new int[] {};
+ mAdditionalPlmns = new ArraySet();
+ mGlobalCellId = null;
+ }
+
/**
*
* @param pci Physical Cell Id in range [0, 1007].
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
index a7e79f93ae89..e01e8f0d5b51 100644
--- a/telephony/java/android/telephony/CellInfoNr.java
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -29,9 +29,16 @@ import java.util.Objects;
public final class CellInfoNr extends CellInfo {
private static final String TAG = "CellInfoNr";
- private final CellIdentityNr mCellIdentity;
+ private CellIdentityNr mCellIdentity;
private final CellSignalStrengthNr mCellSignalStrength;
+ /** @hide */
+ public CellInfoNr() {
+ super();
+ mCellIdentity = new CellIdentityNr();
+ mCellSignalStrength = new CellSignalStrengthNr();
+ }
+
private CellInfoNr(Parcel in) {
super(in);
mCellIdentity = CellIdentityNr.CREATOR.createFromParcel(in);
@@ -71,6 +78,11 @@ public final class CellInfoNr extends CellInfo {
return mCellIdentity;
}
+ /** @hide */
+ public void setCellIdentity(CellIdentityNr cid) {
+ mCellIdentity = cid;
+ }
+
/**
* @return a {@link CellSignalStrengthNr} instance.
*/
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f9148d0c44c4..7a7792242c12 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9231,7 +9231,7 @@ public class TelephonyManager {
* app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param enable Whether to enable mobile data.
- * @deprecated use setDataEnabledWithReason with reason DATA_ENABLED_REASON_USER instead.
+ * @deprecated use setDataEnabledForReason with reason DATA_ENABLED_REASON_USER instead.
*
*/
@Deprecated
@@ -9243,16 +9243,16 @@ public class TelephonyManager {
/**
* @hide
- * @deprecated use {@link #setDataEnabledWithReason(int, boolean)} instead.
+ * @deprecated use {@link #setDataEnabledForReason(int, boolean)} instead.
*/
@SystemApi
@Deprecated
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void setDataEnabled(int subId, boolean enable) {
try {
- setDataEnabledWithReason(subId, DATA_ENABLED_REASON_USER, enable);
+ setDataEnabledForReason(subId, DATA_ENABLED_REASON_USER, enable);
} catch (RuntimeException e) {
- Log.e(TAG, "Error calling setDataEnabledWithReason e:" + e);
+ Log.e(TAG, "Error calling setDataEnabledForReason e:" + e);
}
}
@@ -9461,9 +9461,9 @@ public class TelephonyManager {
@SystemApi
public boolean getDataEnabled(int subId) {
try {
- return isDataEnabledWithReason(DATA_ENABLED_REASON_USER);
+ return isDataEnabledForReason(DATA_ENABLED_REASON_USER);
} catch (RuntimeException e) {
- Log.e(TAG, "Error calling isDataEnabledWithReason e:" + e);
+ Log.e(TAG, "Error calling isDataEnabledForReason e:" + e);
}
return false;
}
@@ -11016,7 +11016,7 @@ public class TelephonyManager {
*
* @param enabled control enable or disable carrier data.
* @see #resetAllCarrierActions()
- * @deprecated use {@link #setDataEnabledWithReason(int, boolean) with
+ * @deprecated use {@link #setDataEnabledForReason(int, boolean) with
* reason {@link #DATA_ENABLED_REASON_CARRIER}} instead.
* @hide
*/
@@ -11025,9 +11025,9 @@ public class TelephonyManager {
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void setCarrierDataEnabled(boolean enabled) {
try {
- setDataEnabledWithReason(DATA_ENABLED_REASON_CARRIER, enabled);
+ setDataEnabledForReason(DATA_ENABLED_REASON_CARRIER, enabled);
} catch (RuntimeException e) {
- Log.e(TAG, "Error calling setDataEnabledWithReason e:" + e);
+ Log.e(TAG, "Error calling setDataEnabledForReason e:" + e);
}
}
@@ -11113,7 +11113,7 @@ public class TelephonyManager {
/**
* Policy control of data connection. Usually used when data limit is passed.
* @param enabled True if enabling the data, otherwise disabling.
- * @deprecated use {@link #setDataEnabledWithReason(int, boolean) with
+ * @deprecated use {@link #setDataEnabledForReason(int, boolean) with
* reason {@link #DATA_ENABLED_REASON_POLICY}} instead.
* @hide
*/
@@ -11121,9 +11121,9 @@ public class TelephonyManager {
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setPolicyDataEnabled(boolean enabled) {
try {
- setDataEnabledWithReason(DATA_ENABLED_REASON_POLICY, enabled);
+ setDataEnabledForReason(DATA_ENABLED_REASON_POLICY, enabled);
} catch (RuntimeException e) {
- Log.e(TAG, "Error calling setDataEnabledWithReason e:" + e);
+ Log.e(TAG, "Error calling setDataEnabledForReason e:" + e);
}
}
@@ -11139,36 +11139,28 @@ public class TelephonyManager {
/**
* To indicate that user enabled or disabled data.
- * @hide
*/
- @SystemApi
public static final int DATA_ENABLED_REASON_USER = 0;
/**
* To indicate that data control due to policy. Usually used when data limit is passed.
* Policy data on/off won't affect user settings but will bypass the
* settings and turns off data internally if set to {@code false}.
- * @hide
*/
- @SystemApi
public static final int DATA_ENABLED_REASON_POLICY = 1;
/**
* To indicate enable or disable carrier data by the system based on carrier signalling or
* carrier privileged apps. Carrier data on/off won't affect user settings but will bypass the
* settings and turns off data internally if set to {@code false}.
- * @hide
*/
- @SystemApi
public static final int DATA_ENABLED_REASON_CARRIER = 2;
/**
* To indicate enable or disable data by thermal service.
* Thermal data on/off won't affect user settings but will bypass the
* settings and turns off data internally if set to {@code false}.
- * @hide
*/
- @SystemApi
public static final int DATA_ENABLED_REASON_THERMAL = 3;
/**
@@ -11197,25 +11189,23 @@ public class TelephonyManager {
* has {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} irrespective of
* the reason.
* @throws IllegalStateException if the Telephony process is not currently available.
- * @hide
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
- @SystemApi
- public void setDataEnabledWithReason(@DataEnabledReason int reason, boolean enabled) {
- setDataEnabledWithReason(getSubId(), reason, enabled);
+ public void setDataEnabledForReason(@DataEnabledReason int reason, boolean enabled) {
+ setDataEnabledForReason(getSubId(), reason, enabled);
}
- private void setDataEnabledWithReason(int subId, @DataEnabledReason int reason,
+ private void setDataEnabledForReason(int subId, @DataEnabledReason int reason,
boolean enabled) {
try {
ITelephony service = getITelephony();
if (service != null) {
- service.setDataEnabledWithReason(subId, reason, enabled);
+ service.setDataEnabledForReason(subId, reason, enabled);
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- Log.e(TAG, "Telephony#setDataEnabledWithReason RemoteException", ex);
+ Log.e(TAG, "Telephony#setDataEnabledForReason RemoteException", ex);
ex.rethrowFromSystemServer();
}
}
@@ -11223,9 +11213,11 @@ public class TelephonyManager {
/**
* Return whether data is enabled for certain reason .
*
- * If {@link #isDataEnabledWithReason} returns false, it means in data enablement for a
+ * If {@link #isDataEnabledForReason} returns false, it means in data enablement for a
* specific reason is turned off. If any of the reason is off, then it will result in
- * bypassing user preference and result in data to be turned off.
+ * bypassing user preference and result in data to be turned off. Call
+ * {@link #isDataConnectionAllowed} in order to know whether
+ * data connection is allowed on the device.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies
* to the given subId. Otherwise, applies to
@@ -11234,27 +11226,26 @@ public class TelephonyManager {
* @param reason the reason the data enable change is taking place
* @return whether data is enabled for a reason.
* <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} or
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}
* @throws IllegalStateException if the Telephony process is not currently available.
- * @hide
*/
@RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
android.Manifest.permission.READ_PHONE_STATE})
- @SystemApi
- public boolean isDataEnabledWithReason(@DataEnabledReason int reason) {
- return isDataEnabledWithReason(getSubId(), reason);
+ public boolean isDataEnabledForReason(@DataEnabledReason int reason) {
+ return isDataEnabledForReason(getSubId(), reason);
}
- private boolean isDataEnabledWithReason(int subId, @DataEnabledReason int reason) {
+ private boolean isDataEnabledForReason(int subId, @DataEnabledReason int reason) {
try {
ITelephony service = getITelephony();
if (service != null) {
- return service.isDataEnabledWithReason(subId, reason);
+ return service.isDataEnabledForReason(subId, reason);
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- Log.e(TAG, "Telephony#isDataEnabledWithReason RemoteException", ex);
+ Log.e(TAG, "Telephony#isDataEnabledForReason RemoteException", ex);
ex.rethrowFromSystemServer();
}
return false;
@@ -11395,10 +11386,14 @@ public class TelephonyManager {
* <LI>And possibly others.</LI>
* </UL>
* @return {@code true} if the overall data connection is allowed; {@code false} if not.
- * @hide
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} or
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE} or
+ * android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE
*/
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE})
public boolean isDataConnectionAllowed() {
boolean retVal = false;
try {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index e2de5c82940f..4021d0a2888f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1015,7 +1015,7 @@ interface ITelephony {
* @param reason the reason the data enable change is taking place
* @param enable true to turn on, else false
*/
- void setDataEnabledWithReason(int subId, int reason, boolean enable);
+ void setDataEnabledForReason(int subId, int reason, boolean enable);
/**
* Return whether data is enabled for certain reason
@@ -1023,7 +1023,7 @@ interface ITelephony {
* @param reason the reason the data enable change is taking place
* @return true on enabled
*/
- boolean isDataEnabledWithReason(int subId, int reason);
+ boolean isDataEnabledForReason(int subId, int reason);
/**
* Checks if manual network selection is allowed.
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 7790043859a0..05a59ef7fc72 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -744,6 +744,15 @@
</intent-filter>
</activity>
+ <activity android:name="BlurActivity"
+ android:label="Shaders/Blur"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
<activity android:name="TextActivity"
android:label="Text/Simple Text"
android:theme="@android:style/Theme.NoTitleBar"
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
new file mode 100644
index 000000000000..033fb0ec35d2
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
@@ -0,0 +1,110 @@
+/*
+ * 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.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.BlurShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class BlurActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setClipChildren(false);
+ layout.setGravity(Gravity.CENTER);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(500, 500);
+ params.bottomMargin = 100;
+
+ layout.addView(new BlurGradientView(this), params);
+ layout.addView(new BlurView(this), params);
+
+ setContentView(layout);
+ }
+
+ public static class BlurGradientView extends View {
+ private BlurShader mBlurShader = null;
+ private Paint mPaint;
+
+ public BlurGradientView(Context c) {
+ super(c);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (changed || mBlurShader == null) {
+ LinearGradient gradient = new LinearGradient(
+ 0f,
+ 0f,
+ right - left,
+ bottom - top,
+ Color.CYAN,
+ Color.YELLOW,
+ Shader.TileMode.CLAMP
+ );
+ mBlurShader = new BlurShader(30f, 40f, gradient);
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaint.setShader(mBlurShader);
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
+ }
+ }
+
+ public static class BlurView extends View {
+
+ private final BlurShader mBlurShader;
+ private final Paint mPaint;
+
+ public BlurView(Context c) {
+ super(c);
+
+ mBlurShader = new BlurShader(20f, 20f, null);
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaint.setShader(mBlurShader);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ mPaint.setColor(Color.BLUE);
+ canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
+
+ mPaint.setColor(Color.RED);
+ canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, 50f, mPaint);
+ }
+ }
+}
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index 76f8df02465b..f55d4d474bfb 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -26,7 +26,7 @@ android_test_helper_app {
java_test_host {
name: "StagedInstallInternalTest",
srcs: ["src/**/*.java"],
- libs: ["tradefed"],
+ libs: ["tradefed", "cts-shim-host-lib"],
static_libs: [
"testng",
"compatibility-tradefed",
@@ -35,6 +35,7 @@ java_test_host {
"cts-install-lib-host",
],
data: [
+ ":com.android.apex.apkrollback.test_v1",
":com.android.apex.cts.shim.v2_prebuilt",
":TestAppAv1",
],
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index 781723985ec5..e5411dee7805 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -47,11 +47,7 @@ import java.util.function.Consumer;
@RunWith(JUnit4.class)
public class StagedInstallInternalTest {
-
- private static final String TAG = StagedInstallInternalTest.class.getSimpleName();
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
- private static final TestApp TEST_APEX_WITH_APK_V1 = new TestApp("TestApexWithApkV1",
- APK_IN_APEX_TESTAPEX_NAME, 1, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v1.apex");
private static final TestApp TEST_APEX_WITH_APK_V2 = new TestApp("TestApexWithApkV2",
APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v2.apex");
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index d7b07967f979..f50d2e134730 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -16,6 +16,8 @@
package com.android.tests.stagedinstallinternal.host;
+import static com.android.cts.shim.lib.ShimPackage.SHIM_APEX_PACKAGE_NAME;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertTrue;
@@ -151,43 +153,78 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
runPhase("testSystemServerRestartDoesNotAffectStagedSessions_Verify");
}
+ // Test waiting time for staged session to be ready using adb staged install can be altered
@Test
- public void testAdbStagedInstallWaitForReadyFlagWorks() throws Exception {
+ public void testAdbStagdReadyTimeoutFlagWorks() throws Exception {
assumeTrue("Device does not support updating APEX",
mHostUtils.isApexUpdateSupported());
- File apexFile = mTestUtils.getTestFile(SHIM_V2);
- String output = getDevice().executeAdbCommand("install", "--staged",
- "--wait-for-staged-ready", "60000", apexFile.getAbsolutePath());
+ final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+ final String output = getDevice().executeAdbCommand("install", "--staged",
+ "--staged-ready-timeout", "60000", apexFile.getAbsolutePath());
assertThat(output).contains("Reboot device to apply staged session");
- String sessionId = getDevice().executeShellCommand(
+ final String sessionId = getDevice().executeShellCommand(
"pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
assertThat(sessionId).isNotEmpty();
}
+ // Test adb staged installation wait for session to be ready by default
@Test
- public void testAdbStagedInstallNoWaitFlagWorks() throws Exception {
+ public void testAdbStagedInstallWaitsTillReadyByDefault() throws Exception {
assumeTrue("Device does not support updating APEX",
mHostUtils.isApexUpdateSupported());
- File apexFile = mTestUtils.getTestFile(SHIM_V2);
- String output = getDevice().executeAdbCommand("install", "--staged",
- "--no-wait", apexFile.getAbsolutePath());
+ final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+ final String output = getDevice().executeAdbCommand("install", "--staged",
+ apexFile.getAbsolutePath());
+ assertThat(output).contains("Reboot device to apply staged session");
+ final String sessionId = getDevice().executeShellCommand(
+ "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
+ assertThat(sessionId).isNotEmpty();
+ }
+
+ // Test we can skip waiting for staged session to be ready
+ @Test
+ public void testAdbStagedReadyWaitCanBeSkipped() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+ final String output = getDevice().executeAdbCommand("install", "--staged",
+ "--staged-ready-timeout", "0", apexFile.getAbsolutePath());
assertThat(output).doesNotContain("Reboot device to apply staged session");
assertThat(output).contains("Success");
- String sessionId = getDevice().executeShellCommand(
+ final String sessionId = getDevice().executeShellCommand(
"pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
assertThat(sessionId).isEmpty();
}
+ // Test rollback-app command waits for staged sessions to be ready
+ @Test
+ public void testAdbRollbackAppWaitsForStagedReady() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+ String output = getDevice().executeAdbCommand("install", "--staged",
+ "--enable-rollback", apexFile.getAbsolutePath());
+ assertThat(output).contains("Reboot device to apply staged session");
+ getDevice().reboot();
+ output = getDevice().executeShellCommand("pm rollback-app " + SHIM_APEX_PACKAGE_NAME);
+ assertThat(output).contains("Reboot device to apply staged session");
+ final String sessionId = getDevice().executeShellCommand(
+ "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
+ assertThat(sessionId).isNotEmpty();
+ }
+
@Test
public void testAdbInstallMultiPackageCommandWorks() throws Exception {
assumeTrue("Device does not support updating APEX",
mHostUtils.isApexUpdateSupported());
- File apexFile = mTestUtils.getTestFile(SHIM_V2);
- File apkFile = mTestUtils.getTestFile(APK_A);
- String output = getDevice().executeAdbCommand("install-multi-package",
+ final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+ final File apkFile = mTestUtils.getTestFile(APK_A);
+ final String output = getDevice().executeAdbCommand("install-multi-package",
apexFile.getAbsolutePath(), apkFile.getAbsolutePath());
assertThat(output).contains("Created parent session");
assertThat(output).contains("Created child session");
@@ -227,16 +264,16 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
private void restartSystemServer() throws Exception {
// Restart the system server
- ProcessInfo oldPs = getDevice().getProcessByName("system_server");
+ final ProcessInfo oldPs = getDevice().getProcessByName("system_server");
getDevice().enableAdbRoot(); // Need root to restart system server
assertThat(getDevice().executeShellCommand("am restart")).contains("Restart the system");
getDevice().disableAdbRoot();
// Wait for new system server process to start
- long start = System.currentTimeMillis();
+ final long start = System.currentTimeMillis();
while (System.currentTimeMillis() < start + SYSTEM_SERVER_TIMEOUT_MS) {
- ProcessInfo newPs = getDevice().getProcessByName("system_server");
+ final ProcessInfo newPs = getDevice().getProcessByName("system_server");
if (newPs != null) {
if (newPs.getPid() != oldPs.getPid()) {
getDevice().waitForDeviceAvailable();
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
index 073ae30aaf1a..ca723b881bbd 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
@@ -157,7 +157,7 @@ public class TaskOrganizerMultiWindowTest extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mOrganizer.registerOrganizer(WINDOWING_MODE_MULTI_WINDOW);
+ mOrganizer.registerOrganizer();
mTaskView1 = new ResizingTaskView(this, makeSettingsIntent());
mTaskView2 = new ResizingTaskView(this, makeContactsIntent());
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
index 8fc5c5d78b60..5ec949391181 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
@@ -57,7 +57,7 @@ public class TaskOrganizerPipTest extends Service {
public void onCreate() {
super.onCreate();
- mOrganizer.registerOrganizer(WINDOWING_MODE_PINNED);
+ mOrganizer.registerOrganizer();
final WindowManager.LayoutParams wlp = new WindowManager.LayoutParams();
wlp.setTitle("TaskOrganizerPipTest");
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index ab12ac0ef56e..5a29c2c96ba7 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -26,19 +26,14 @@ import static android.Manifest.permission.UPDATE_DEVICE_STATS;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_OEM;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_REQUIRED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
-import static android.net.INetd.PERMISSION_INTERNET;
-import static android.net.INetd.PERMISSION_NONE;
-import static android.net.INetd.PERMISSION_SYSTEM;
-import static android.net.INetd.PERMISSION_UNINSTALLED;
-import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS;
-import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.Process.SYSTEM_UID;
import static com.android.server.connectivity.PermissionMonitor.NETWORK;
import static com.android.server.connectivity.PermissionMonitor.SYSTEM;
-import static com.android.server.connectivity.PermissionMonitor.UidNetdPermissionInfo;
import static junit.framework.Assert.fail;
@@ -69,7 +64,7 @@ import android.net.UidRange;
import android.os.Build;
import android.os.UserHandle;
import android.os.UserManager;
-import android.util.SparseArray;
+import android.util.SparseIntArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -102,6 +97,7 @@ public class PermissionMonitorTest {
private static final int SYSTEM_UID1 = 1000;
private static final int SYSTEM_UID2 = 1008;
private static final int VPN_UID = 10002;
+ private static final String REAL_SYSTEM_PACKAGE_NAME = "android";
private static final String MOCK_PACKAGE1 = "appName1";
private static final String MOCK_PACKAGE2 = "appName2";
private static final String SYSTEM_PACKAGE1 = "sysName1";
@@ -132,7 +128,6 @@ public class PermissionMonitorTest {
new UserInfo(MOCK_USER1, "", 0),
new UserInfo(MOCK_USER2, "", 0),
}));
- doReturn(PackageManager.PERMISSION_DENIED).when(mDeps).uidPermission(anyString(), anyInt());
mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
@@ -145,15 +140,35 @@ public class PermissionMonitorTest {
verify(mMockPmi).getPackageList(mPermissionMonitor);
}
- private boolean wouldBeCarryoverPackage(String partition, int targetSdkVersion, int uid) {
- final PackageInfo packageInfo = buildPackageInfo(partition, uid, MOCK_USER1);
+ private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
+ String... permissions) {
+ final PackageInfo packageInfo =
+ packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, permissions, partition);
packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
- return mPermissionMonitor.isCarryoverPackage(packageInfo.applicationInfo);
+ packageInfo.applicationInfo.uid = uid;
+ return mPermissionMonitor.hasRestrictedNetworkPermission(packageInfo);
+ }
+
+ private static PackageInfo systemPackageInfoWithPermissions(String... permissions) {
+ return packageInfoWithPermissions(
+ REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
}
- private static PackageInfo packageInfoWithPartition(String partition) {
+ private static PackageInfo vendorPackageInfoWithPermissions(String... permissions) {
+ return packageInfoWithPermissions(
+ REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_VENDOR);
+ }
+
+ private static PackageInfo packageInfoWithPermissions(int permissionsFlags,
+ String[] permissions, String partition) {
+ int[] requestedPermissionsFlags = new int[permissions.length];
+ for (int i = 0; i < permissions.length; i++) {
+ requestedPermissionsFlags[i] = permissionsFlags;
+ }
final PackageInfo packageInfo = new PackageInfo();
+ packageInfo.requestedPermissions = permissions;
packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.requestedPermissionsFlags = requestedPermissionsFlags;
int privateFlags = 0;
switch (partition) {
case PARTITION_OEM:
@@ -170,145 +185,168 @@ public class PermissionMonitorTest {
return packageInfo;
}
- private static PackageInfo buildPackageInfo(String partition, int uid, int userId) {
- final PackageInfo pkgInfo = packageInfoWithPartition(partition);
+ private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid, int userId) {
+ final PackageInfo pkgInfo;
+ if (hasSystemPermission) {
+ pkgInfo = systemPackageInfoWithPermissions(
+ CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ } else {
+ pkgInfo = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, new String[] {}, "");
+ }
pkgInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
return pkgInfo;
}
- /** This will REMOVE all previously set permissions from given uid. */
- private void removeAllPermissions(int uid) {
- doReturn(PackageManager.PERMISSION_DENIED).when(mDeps).uidPermission(anyString(), eq(uid));
- }
-
- /** Set up mocks so that given UID has the requested permissions. */
- private void addPermissions(int uid, String... permissions) {
- for (String permission : permissions) {
- doReturn(PackageManager.PERMISSION_GRANTED)
- .when(mDeps).uidPermission(eq(permission), eq(uid));
- }
- }
-
@Test
public void testHasPermission() {
- addPermissions(MOCK_UID1);
- assertFalse(mPermissionMonitor.hasPermission(CHANGE_NETWORK_STATE, MOCK_UID1));
- assertFalse(mPermissionMonitor.hasPermission(NETWORK_STACK, MOCK_UID1));
- assertFalse(mPermissionMonitor.hasPermission(
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID1));
- assertFalse(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID1));
-
- addPermissions(MOCK_UID1, CHANGE_NETWORK_STATE, NETWORK_STACK);
- assertTrue(mPermissionMonitor.hasPermission(CHANGE_NETWORK_STATE, MOCK_UID1));
- assertTrue(mPermissionMonitor.hasPermission(NETWORK_STACK, MOCK_UID1));
- assertFalse(mPermissionMonitor.hasPermission(
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID1));
- assertFalse(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID1));
- assertFalse(mPermissionMonitor.hasPermission(CHANGE_NETWORK_STATE, MOCK_UID2));
- assertFalse(mPermissionMonitor.hasPermission(NETWORK_STACK, MOCK_UID2));
-
- addPermissions(MOCK_UID2, CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL);
- assertFalse(mPermissionMonitor.hasPermission(
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID1));
- assertFalse(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID1));
- assertTrue(mPermissionMonitor.hasPermission(
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID2));
- assertTrue(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID2));
+ PackageInfo app = systemPackageInfoWithPermissions();
+ assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+ assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+
+ app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE, NETWORK_STACK);
+ assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+ assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+
+ app = systemPackageInfoWithPermissions(
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL);
+ assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+ assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
+ assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+
+ app = packageInfoWithPermissions(REQUESTED_PERMISSION_REQUIRED, new String[] {
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL, NETWORK_STACK },
+ PARTITION_SYSTEM);
+ assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+ assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+
+ app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
+ app.requestedPermissions = null;
+ assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+
+ app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
+ app.requestedPermissionsFlags = null;
+ assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
}
@Test
public void testIsVendorApp() {
- PackageInfo app = packageInfoWithPartition(PARTITION_SYSTEM);
+ PackageInfo app = systemPackageInfoWithPermissions();
assertFalse(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPartition(PARTITION_OEM);
+ app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED,
+ new String[] {}, PARTITION_OEM);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPartition(PARTITION_PRODUCT);
+ app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED,
+ new String[] {}, PARTITION_PRODUCT);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPartition(PARTITION_VENDOR);
+ app = vendorPackageInfoWithPermissions();
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
}
- /**
- * Remove all permissions from the uid then setup permissions to uid for checking restricted
- * network permission.
- */
- private void assertRestrictedNetworkPermission(boolean hasPermission, int uid,
- String... permissions) {
- removeAllPermissions(uid);
- addPermissions(uid, permissions);
- assertEquals(hasPermission, mPermissionMonitor.hasRestrictedNetworkPermission(uid));
+ @Test
+ public void testHasNetworkPermission() {
+ PackageInfo app = systemPackageInfoWithPermissions();
+ assertFalse(mPermissionMonitor.hasNetworkPermission(app));
+ app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
+ assertTrue(mPermissionMonitor.hasNetworkPermission(app));
+ app = systemPackageInfoWithPermissions(NETWORK_STACK);
+ assertFalse(mPermissionMonitor.hasNetworkPermission(app));
+ app = systemPackageInfoWithPermissions(CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ assertFalse(mPermissionMonitor.hasNetworkPermission(app));
+ app = systemPackageInfoWithPermissions(CONNECTIVITY_INTERNAL);
+ assertFalse(mPermissionMonitor.hasNetworkPermission(app));
}
@Test
public void testHasRestrictedNetworkPermission() {
- assertRestrictedNetworkPermission(false, MOCK_UID1);
- assertRestrictedNetworkPermission(false, MOCK_UID1, CHANGE_NETWORK_STATE);
- assertRestrictedNetworkPermission(true, MOCK_UID1, NETWORK_STACK);
- assertRestrictedNetworkPermission(false, MOCK_UID1, CONNECTIVITY_INTERNAL);
- assertRestrictedNetworkPermission(true, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
- assertRestrictedNetworkPermission(false, MOCK_UID1, CHANGE_WIFI_STATE);
- assertRestrictedNetworkPermission(true, MOCK_UID1, PERMISSION_MAINLINE_NETWORK_STACK);
-
- assertFalse(mPermissionMonitor.hasRestrictedNetworkPermission(MOCK_UID2));
- assertFalse(mPermissionMonitor.hasRestrictedNetworkPermission(SYSTEM_UID));
+ assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
+
+ assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
}
@Test
- public void testIsCarryoverPackage() {
+ public void testHasRestrictedNetworkPermissionSystemUid() {
doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
- assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
- assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
- assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
- assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
- assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
- assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
+ assertTrue(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_INTERNAL));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
- assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
- assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
- assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
-
- assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, MOCK_UID1));
- assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, MOCK_UID1));
+ assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_INTERNAL));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ }
+
+ @Test
+ public void testHasRestrictedNetworkPermissionVendorApp() {
+ assertTrue(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
+
+ assertFalse(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE));
}
private void assertBackgroundPermission(boolean hasPermission, String name, int uid,
String... permissions) throws Exception {
when(mPackageManager.getPackageInfo(eq(name), anyInt()))
- .thenReturn(buildPackageInfo(PARTITION_SYSTEM, uid, MOCK_USER1));
- addPermissions(uid, permissions);
+ .thenReturn(packageInfoWithPermissions(
+ REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM));
mPermissionMonitor.onPackageAdded(name, uid);
assertEquals(hasPermission, mPermissionMonitor.hasUseBackgroundNetworksPermission(uid));
}
@Test
public void testHasUseBackgroundNetworksPermission() throws Exception {
- assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID1));
- assertBackgroundPermission(false, "mock1", MOCK_UID1);
- assertBackgroundPermission(false, "mock2", MOCK_UID1, CONNECTIVITY_INTERNAL);
- assertBackgroundPermission(true, "mock3", MOCK_UID1, NETWORK_STACK);
+ assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID));
+ assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID);
+ assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID, CONNECTIVITY_INTERNAL);
+ assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, CHANGE_NETWORK_STATE);
+ assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, NETWORK_STACK);
- assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID2));
- assertBackgroundPermission(false, "mock4", MOCK_UID2);
- assertBackgroundPermission(true, "mock5", MOCK_UID2,
+ assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID1));
+ assertBackgroundPermission(false, MOCK_PACKAGE1, MOCK_UID1);
+ assertBackgroundPermission(true, MOCK_PACKAGE1, MOCK_UID1,
CONNECTIVITY_USE_RESTRICTED_NETWORKS);
- doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
- assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID));
- assertBackgroundPermission(false, "system1", SYSTEM_UID);
- assertBackgroundPermission(true, "system2", SYSTEM_UID, CHANGE_NETWORK_STATE);
- doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
- removeAllPermissions(SYSTEM_UID);
- assertBackgroundPermission(true, "system3", SYSTEM_UID);
+ assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID2));
+ assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2);
+ assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2,
+ CONNECTIVITY_INTERNAL);
+ assertBackgroundPermission(true, MOCK_PACKAGE2, MOCK_UID2, NETWORK_STACK);
}
private class NetdMonitor {
@@ -318,7 +356,7 @@ public class PermissionMonitorTest {
// Add hook to verify and track result of setPermission.
doAnswer((InvocationOnMock invocation) -> {
final Object[] args = invocation.getArguments();
- final Boolean isSystem = args[0].equals(PERMISSION_SYSTEM);
+ final Boolean isSystem = args[0].equals(INetd.PERMISSION_SYSTEM);
for (final int uid : (int[]) args[1]) {
// TODO: Currently, permission monitor will send duplicate commands for each uid
// corresponding to each user. Need to fix that and uncomment below test.
@@ -378,14 +416,13 @@ public class PermissionMonitorTest {
// MOCK_UID1: MOCK_PACKAGE1 only has network permission.
// SYSTEM_UID: SYSTEM_PACKAGE1 has system permission.
// SYSTEM_UID: SYSTEM_PACKAGE2 only has network permission.
- doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM),
- anyString(), anyInt());
+ doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM), anyString());
doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(SYSTEM_PACKAGE1), anyInt());
+ eq(SYSTEM_PACKAGE1));
doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(SYSTEM_PACKAGE2), anyInt());
+ eq(SYSTEM_PACKAGE2));
doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(MOCK_PACKAGE1), anyInt());
+ eq(MOCK_PACKAGE1));
// Add SYSTEM_PACKAGE2, expect only have network permission.
mPermissionMonitor.onUserAdded(MOCK_USER1);
@@ -436,15 +473,13 @@ public class PermissionMonitorTest {
public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception {
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
Arrays.asList(new PackageInfo[] {
- buildPackageInfo(PARTITION_SYSTEM, SYSTEM_UID1, MOCK_USER1),
- buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1),
- buildPackageInfo(PARTITION_SYSTEM, MOCK_UID2, MOCK_USER1),
- buildPackageInfo(PARTITION_SYSTEM, VPN_UID, MOCK_USER1)
+ buildPackageInfo(/* SYSTEM */ true, SYSTEM_UID1, MOCK_USER1),
+ buildPackageInfo(/* SYSTEM */ false, MOCK_UID1, MOCK_USER1),
+ buildPackageInfo(/* SYSTEM */ false, MOCK_UID2, MOCK_USER1),
+ buildPackageInfo(/* SYSTEM */ false, VPN_UID, MOCK_USER1)
}));
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
- buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1));
- addPermissions(SYSTEM_UID,
- CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
mPermissionMonitor.startMonitoring();
// Every app on user 0 except MOCK_UID2 are under VPN.
final Set<UidRange> vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] {
@@ -489,11 +524,11 @@ public class PermissionMonitorTest {
public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception {
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
Arrays.asList(new PackageInfo[] {
- buildPackageInfo(PARTITION_SYSTEM, SYSTEM_UID1, MOCK_USER1),
- buildPackageInfo(PARTITION_SYSTEM, VPN_UID, MOCK_USER1)
+ buildPackageInfo(true, SYSTEM_UID1, MOCK_USER1),
+ buildPackageInfo(false, VPN_UID, MOCK_USER1)
}));
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
- buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1));
+ buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
mPermissionMonitor.startMonitoring();
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1));
@@ -561,48 +596,47 @@ public class PermissionMonitorTest {
// SYSTEM_UID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission.
// SYSTEM_UID2: SYSTEM_PACKAGE2 has only update device stats permission.
- final SparseArray<UidNetdPermissionInfo> uidsPermInfo = new SparseArray<>();
- uidsPermInfo.put(MOCK_UID1, new UidNetdPermissionInfo(PERMISSION_INTERNET));
- uidsPermInfo.put(MOCK_UID2, new UidNetdPermissionInfo(PERMISSION_NONE));
- uidsPermInfo.put(SYSTEM_UID1, new UidNetdPermissionInfo(
- PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS));
- uidsPermInfo.put(SYSTEM_UID2, new UidNetdPermissionInfo(PERMISSION_UPDATE_DEVICE_STATS));
+ SparseIntArray netdPermissionsAppIds = new SparseIntArray();
+ netdPermissionsAppIds.put(MOCK_UID1, INetd.PERMISSION_INTERNET);
+ netdPermissionsAppIds.put(MOCK_UID2, INetd.PERMISSION_NONE);
+ netdPermissionsAppIds.put(SYSTEM_UID1, INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS);
+ netdPermissionsAppIds.put(SYSTEM_UID2, INetd.PERMISSION_UPDATE_DEVICE_STATS);
// Send the permission information to netd, expect permission updated.
- mPermissionMonitor.sendPackagePermissionsToNetd(uidsPermInfo);
+ mPermissionMonitor.sendPackagePermissionsToNetd(netdPermissionsAppIds);
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET,
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET,
new int[]{MOCK_UID1});
- mNetdServiceMonitor.expectPermission(PERMISSION_NONE, new int[]{MOCK_UID2});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1});
- mNetdServiceMonitor.expectPermission(PERMISSION_UPDATE_DEVICE_STATS,
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID2});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UPDATE_DEVICE_STATS,
new int[]{SYSTEM_UID2});
// Update permission of MOCK_UID1, expect new permission show up.
- mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1, new UidNetdPermissionInfo(
- PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS));
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1,
+ INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Change permissions of SYSTEM_UID2, expect new permission show up and old permission
// revoked.
- mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2, new UidNetdPermissionInfo(
- PERMISSION_INTERNET));
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{SYSTEM_UID2});
+ mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2,
+ INetd.PERMISSION_INTERNET);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{SYSTEM_UID2});
// Revoke permission from SYSTEM_UID1, expect no permission stored.
- mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, new UidNetdPermissionInfo(
- PERMISSION_NONE));
- mNetdServiceMonitor.expectPermission(PERMISSION_NONE, new int[]{SYSTEM_UID1});
+ mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.PERMISSION_NONE);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{SYSTEM_UID1});
}
private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions)
throws Exception {
- final PackageInfo packageInfo = buildPackageInfo(PARTITION_SYSTEM, uid, MOCK_USER1);
+ PackageInfo packageInfo = packageInfoWithPermissions(
+ REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
when(mPackageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(packageInfo);
when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[]{packageName});
- addPermissions(uid, permissions);
return packageInfo;
}
@@ -618,30 +652,31 @@ public class PermissionMonitorTest {
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
addPackage(MOCK_PACKAGE2, MOCK_UID2, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID2});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID2});
}
@Test
public void testPackageInstallSharedUid() throws Exception {
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ PackageInfo packageInfo1 = addPackage(MOCK_PACKAGE1, MOCK_UID1,
+ new String[] {INTERNET, UPDATE_DEVICE_STATS});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Install another package with the same uid and no permissions should not cause the UID to
// lose permissions.
- final PackageInfo packageInfo2 = buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1);
+ PackageInfo packageInfo2 = systemPackageInfoWithPermissions();
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
when(mPackageManager.getPackagesForUid(MOCK_UID1))
.thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
mPermissionMonitor.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
}
@Test
@@ -649,12 +684,12 @@ public class PermissionMonitorTest {
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
}
@Test
@@ -662,16 +697,15 @@ public class PermissionMonitorTest {
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
- removeAllPermissions(MOCK_UID1);
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
}
@Test
@@ -679,10 +713,10 @@ public class PermissionMonitorTest {
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {});
- mNetdServiceMonitor.expectPermission(PERMISSION_NONE, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID1});
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
}
@Test
@@ -690,19 +724,17 @@ public class PermissionMonitorTest {
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Mock another package with the same uid but different permissions.
- final PackageInfo packageInfo2 = buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1);
+ PackageInfo packageInfo2 = systemPackageInfoWithPermissions(INTERNET);
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{
MOCK_PACKAGE2});
- removeAllPermissions(MOCK_UID1);
- addPermissions(MOCK_UID1, INTERNET);
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
}
@Test
@@ -711,6 +743,9 @@ public class PermissionMonitorTest {
// necessary permission.
final Context realContext = InstrumentationRegistry.getContext();
final PermissionMonitor monitor = new PermissionMonitor(realContext, mNetdService);
- assertTrue(monitor.hasPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, SYSTEM_UID));
+ final PackageManager manager = realContext.getPackageManager();
+ final PackageInfo systemInfo = manager.getPackageInfo(REAL_SYSTEM_PACKAGE_NAME,
+ GET_PERMISSIONS | MATCH_ANY_USER);
+ assertTrue(monitor.hasPermission(systemInfo, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
}
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
index 6dc4fced19a2..8f093779da11 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
@@ -30,6 +30,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.net.NetworkTemplate;
import android.os.test.TestLooper;
@@ -135,6 +136,11 @@ public final class NetworkStatsSubscriptionsMonitorTest {
mMonitor.onSubscriptionsChanged();
}
+ private void updateSubscriberIdForTestSub(int subId, @Nullable final String subscriberId) {
+ when(mTelephonyManager.getSubscriberId(subId)).thenReturn(subscriberId);
+ mMonitor.onSubscriptionsChanged();
+ }
+
private void removeTestSub(int subId) {
// Remove subId from TestSubList.
mTestSubList.removeIf(it -> it == subId);
@@ -268,4 +274,54 @@ public final class NetworkStatsSubscriptionsMonitorTest {
listener.onServiceStateChanged(serviceState);
assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR);
}
+
+ @Test
+ public void testSubscriberIdUnavailable() {
+ final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
+ ArgumentCaptor.forClass(RatTypeListener.class);
+
+ mMonitor.start();
+ // Insert sim1, set subscriberId to null which is normal in SIM PIN locked case.
+ // Verify RAT type is NETWORK_TYPE_UNKNOWN and service will not perform listener
+ // registration.
+ addTestSub(TEST_SUBID1, null);
+ verify(mTelephonyManager, never()).listen(any(), anyInt());
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+
+ // Set IMSI for sim1, verify the listener will be registered.
+ updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI1);
+ verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(),
+ eq(PhoneStateListener.LISTEN_SERVICE_STATE));
+ reset(mTelephonyManager);
+ when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
+
+ // Set RAT type of sim1 to UMTS. Verify RAT type of sim1 is changed.
+ setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+ TelephonyManager.NETWORK_TYPE_UMTS);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+ reset(mDelegate);
+
+ // Set IMSI to null again to simulate somehow IMSI is not available, such as
+ // modem crash. Verify service should not unregister listener.
+ updateSubscriberIdForTestSub(TEST_SUBID1, null);
+ verify(mTelephonyManager, never()).listen(any(), anyInt());
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+ reset(mDelegate);
+
+ // Set RAT type of sim1 to LTE. Verify RAT type of sim1 is still changed even if the IMSI
+ // is not available. The monitor keeps the listener even if the IMSI disappears because
+ // the IMSI can never change for any given subId, therefore even if the IMSI is updated
+ // to null, the monitor should continue accepting updates of the RAT type. However,
+ // telephony is never actually supposed to do this, if the IMSI disappears there should
+ // not be updates, but it's still the right thing to do theoretically.
+ setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE);
+ reset(mDelegate);
+
+ mMonitor.stop();
+ verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()),
+ eq(PhoneStateListener.LISTEN_NONE));
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ }
}
diff --git a/tools/preload-check/Android.bp b/tools/preload-check/Android.bp
index 87b31d22af32..aaa6d76b39e3 100644
--- a/tools/preload-check/Android.bp
+++ b/tools/preload-check/Android.bp
@@ -15,7 +15,7 @@
java_test_host {
name: "PreloadCheck",
srcs: ["src/**/*.java"],
- java_resources: [":preloaded-classes-blacklist"],
+ java_resources: [":preloaded-classes-denylist"],
libs: ["tradefed"],
test_suites: ["general-tests"],
required: ["preload-check-device"],
diff --git a/tools/preload-check/src/com/android/preload/check/PreloadCheck.java b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java
index 00fd414e3ee2..3d851531d7e7 100644
--- a/tools/preload-check/src/com/android/preload/check/PreloadCheck.java
+++ b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java
@@ -69,13 +69,13 @@ public class PreloadCheck implements IDeviceTest {
}
/**
- * Test the classes mentioned in the embedded preloaded-classes blacklist.
+ * Test the classes mentioned in the embedded preloaded-classes denylist.
*/
@Test
- public void testBlackList() throws Exception {
+ public void testDenyList() throws Exception {
StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(new InputStreamReader(getClass()
- .getResourceAsStream("/preloaded-classes-blacklist")))) {
+ .getResourceAsStream("/preloaded-classes-denylist")))) {
String s;
while ((s = br.readLine()) != null) {
s = s.trim();
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index 53c3b33d9845..ee7320f9a5ef 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -487,6 +487,7 @@ package android.net.wifi {
method @Nullable public String getPassphrase();
method @Nullable public android.net.wifi.hotspot2.PasspointConfiguration getPasspointConfig();
method @IntRange(from=0) public int getPriority();
+ method public int getPriorityGroup();
method @Nullable public String getSsid();
method public boolean isAppInteractionRequired();
method public boolean isCredentialSharedWithUser();
@@ -513,6 +514,7 @@ package android.net.wifi {
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserInteractionRequired(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPasspointConfig(@NonNull android.net.wifi.hotspot2.PasspointConfiguration);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(@IntRange(from=0) int);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriorityGroup(int);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setSsid(@NonNull String);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setUntrusted(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiEnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 68eb1bbd8a79..a3c4ae764612 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -102,10 +102,15 @@ public final class WifiNetworkSuggestion implements Parcelable {
*/
private int mMeteredOverride;
/**
- * Priority of this network among other network suggestions provided by the app.
+ * Priority of this network among other network suggestions from same priority group
+ * provided by the app.
* The lower the number, the higher the priority (i.e value of 0 = highest priority).
*/
private int mPriority;
+ /**
+ * Priority group ID, while suggestion priority will only effect inside the priority group.
+ */
+ private int mPriorityGroup;
/**
* The carrier ID identifies the operator who provides this network configuration.
@@ -165,6 +170,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
mWapiPskPassphrase = null;
mWapiEnterpriseConfig = null;
mIsNetworkUntrusted = false;
+ mPriorityGroup = 0;
}
/**
@@ -329,6 +335,18 @@ public final class WifiNetworkSuggestion implements Parcelable {
}
/**
+ * Set the priority group ID, {@link #setPriority(int)} will only impact the network
+ * suggestions from the same priority group within the same app.
+ *
+ * @param priorityGroup priority group id, if not set default is 0.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setPriorityGroup(int priorityGroup) {
+ mPriorityGroup = priorityGroup;
+ return this;
+ }
+
+ /**
* Set the ASCII WAPI passphrase for this network. Needed for authenticating to
* WAPI-PSK networks.
*
@@ -411,8 +429,9 @@ public final class WifiNetworkSuggestion implements Parcelable {
/**
* Specify the priority of this network among other network suggestions provided by the same
- * app (priorities have no impact on suggestions by different apps). The higher the number,
- * the higher the priority (i.e value of 0 = lowest priority).
+ * app (priorities have no impact on suggestions by different apps) and within the same
+ * priority group, see {@link #setPriorityGroup(int)}.
+ * The higher the number, the higher the priority (i.e value of 0 = lowest priority).
* <p>
* <li>If not set, defaults a lower priority than any assigned priority.</li>
*
@@ -696,7 +715,8 @@ public final class WifiNetworkSuggestion implements Parcelable {
mIsAppInteractionRequired,
mIsUserInteractionRequired,
mIsSharedWithUser,
- mIsInitialAutojoinEnabled);
+ mIsInitialAutojoinEnabled,
+ mPriorityGroup);
}
}
@@ -739,6 +759,12 @@ public final class WifiNetworkSuggestion implements Parcelable {
*/
public final boolean isInitialAutoJoinEnabled;
+ /**
+ * Priority group ID.
+ * @hide
+ */
+ public final int priorityGroup;
+
/** @hide */
public WifiNetworkSuggestion() {
this.wifiConfiguration = new WifiConfiguration();
@@ -747,6 +773,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
this.isUserInteractionRequired = false;
this.isUserAllowedToManuallyConnect = true;
this.isInitialAutoJoinEnabled = true;
+ this.priorityGroup = 0;
}
/** @hide */
@@ -755,7 +782,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
boolean isAppInteractionRequired,
boolean isUserInteractionRequired,
boolean isUserAllowedToManuallyConnect,
- boolean isInitialAutoJoinEnabled) {
+ boolean isInitialAutoJoinEnabled, int priorityGroup) {
checkNotNull(networkConfiguration);
this.wifiConfiguration = networkConfiguration;
this.passpointConfiguration = passpointConfiguration;
@@ -764,6 +791,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
this.isUserInteractionRequired = isUserInteractionRequired;
this.isUserAllowedToManuallyConnect = isUserAllowedToManuallyConnect;
this.isInitialAutoJoinEnabled = isInitialAutoJoinEnabled;
+ this.priorityGroup = priorityGroup;
}
public static final @NonNull Creator<WifiNetworkSuggestion> CREATOR =
@@ -776,7 +804,8 @@ public final class WifiNetworkSuggestion implements Parcelable {
in.readBoolean(), // isAppInteractionRequired
in.readBoolean(), // isUserInteractionRequired
in.readBoolean(), // isSharedCredentialWithUser
- in.readBoolean() // isAutojoinEnabled
+ in.readBoolean(), // isAutojoinEnabled
+ in.readInt() // priorityGroup
);
}
@@ -799,6 +828,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
dest.writeBoolean(isUserInteractionRequired);
dest.writeBoolean(isUserAllowedToManuallyConnect);
dest.writeBoolean(isInitialAutoJoinEnabled);
+ dest.writeInt(priorityGroup);
}
@Override
@@ -842,6 +872,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
.append(", isCredentialSharedWithUser=").append(isUserAllowedToManuallyConnect)
.append(", isInitialAutoJoinEnabled=").append(isInitialAutoJoinEnabled)
.append(", isUnTrusted=").append(!wifiConfiguration.trusted)
+ .append(", priorityGroup=").append(priorityGroup)
.append(" ]");
return sb.toString();
}
@@ -962,4 +993,11 @@ public final class WifiNetworkSuggestion implements Parcelable {
}
return WifiInfo.removeDoubleQuotes(wifiConfiguration.preSharedKey);
}
+
+ /**
+ * @see Builder#setPriorityGroup(int)
+ */
+ public int getPriorityGroup() {
+ return priorityGroup;
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index f0839e9b3122..3744a5183793 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -16,7 +16,12 @@
package android.net.wifi;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import android.net.MacAddress;
import android.net.wifi.hotspot2.PasspointConfiguration;
@@ -39,6 +44,8 @@ public class WifiNetworkSuggestionTest {
private static final String TEST_FQDN = "fqdn";
private static final String TEST_WAPI_CERT_SUITE = "suite";
private static final String TEST_DOMAIN_SUFFIX_MATCH = "domainSuffixMatch";
+ private static final int DEFAULT_PRIORITY_GROUP = 0;
+ private static final int TEST_PRIORITY_GROUP = 1;
/**
* Validate correctness of WifiNetworkSuggestion object created by
@@ -612,7 +619,7 @@ public class WifiNetworkSuggestionTest {
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion(
- configuration, null, false, true, true, true);
+ configuration, null, false, true, true, true, TEST_PRIORITY_GROUP);
Parcel parcelW = Parcel.obtain();
suggestion.writeToParcel(parcelW, 0);
@@ -683,14 +690,16 @@ public class WifiNetworkSuggestionTest {
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, true, false, true, true);
+ new WifiNetworkSuggestion(configuration, null, true, false, true, true,
+ TEST_PRIORITY_GROUP);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.BSSID = TEST_BSSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, true, true, true);
+ new WifiNetworkSuggestion(configuration1, null, false, true, true, true,
+ DEFAULT_PRIORITY_GROUP);
assertEquals(suggestion, suggestion1);
assertEquals(suggestion.hashCode(), suggestion1.hashCode());
@@ -706,13 +715,15 @@ public class WifiNetworkSuggestionTest {
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID_1;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
assertNotEquals(suggestion, suggestion1);
}
@@ -728,13 +739,15 @@ public class WifiNetworkSuggestionTest {
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
assertNotEquals(suggestion, suggestion1);
}
@@ -749,13 +762,15 @@ public class WifiNetworkSuggestionTest {
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
assertNotEquals(suggestion, suggestion1);
}