summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ApiDocs.bp16
-rw-r--r--OWNERS1
-rw-r--r--TRACE_OWNERS5
-rw-r--r--apex/jobscheduler/framework/java/android/app/AlarmManager.java10
-rw-r--r--apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java4
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java74
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java232
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java6
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java3
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java10
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java6
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java4
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java6
-rw-r--r--cmds/bootanimation/BootAnimation.cpp16
-rw-r--r--cmds/bootanimation/BootAnimation.h1
-rw-r--r--core/api/current.txt22
-rw-r--r--core/api/system-current.txt11
-rw-r--r--core/api/test-current.txt8
-rw-r--r--core/java/android/accessibilityservice/MagnificationConfig.java13
-rw-r--r--core/java/android/app/Activity.java4
-rw-r--r--core/java/android/app/ActivityManager.java6
-rw-r--r--core/java/android/app/Dialog.java4
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl6
-rw-r--r--core/java/android/app/IUidObserver.aidl7
-rw-r--r--core/java/android/app/LocaleManager.java28
-rw-r--r--core/java/android/app/TaskInfo.java3
-rw-r--r--core/java/android/app/UiAutomation.java4
-rw-r--r--core/java/android/app/WindowConfiguration.java3
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java254
-rw-r--r--core/java/android/app/ambientcontext/IAmbientContextManager.aidl4
-rw-r--r--core/java/android/companion/virtual/IVirtualDevice.aidl6
-rw-r--r--core/java/android/companion/virtual/VirtualDeviceManager.java73
-rw-r--r--core/java/android/companion/virtual/audio/IAudioConfigChangedCallback.aidl (renamed from core/java/android/companion/virtual/audio/IAudioSessionCallback.aidl)10
-rw-r--r--core/java/android/companion/virtual/audio/IAudioRoutingCallback.aidl28
-rw-r--r--core/java/android/companion/virtual/audio/VirtualAudioDevice.java10
-rw-r--r--core/java/android/companion/virtual/audio/VirtualAudioSession.java62
-rw-r--r--core/java/android/content/AbstractThreadedSyncAdapter.java13
-rw-r--r--core/java/android/content/ClipDescription.java20
-rw-r--r--core/java/android/content/pm/OWNERS1
-rw-r--r--core/java/android/content/pm/PackageManager.java2
-rw-r--r--core/java/android/hardware/display/AmbientDisplayConfiguration.java131
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java27
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl10
-rw-r--r--core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl2
-rw-r--r--core/java/android/hardware/location/OWNERS7
-rw-r--r--core/java/android/hardware/usb/UsbManager.java34
-rw-r--r--core/java/android/os/OWNERS3
-rw-r--r--core/java/android/os/Parcel.java3
-rw-r--r--core/java/android/os/PowerManager.java10
-rw-r--r--core/java/android/os/Trace.java47
-rw-r--r--core/java/android/print/IPrintManager.aidl9
-rw-r--r--core/java/android/print/PrintManager.java19
-rw-r--r--core/java/android/provider/Settings.java23
-rw-r--r--core/java/android/service/autofill/FillRequest.java21
-rw-r--r--core/java/android/speech/RecognitionSupport.java220
-rw-r--r--core/java/android/util/SparseSetArray.java19
-rw-r--r--core/java/android/view/OWNERS1
-rw-r--r--core/java/android/view/TextureView.java41
-rw-r--r--core/java/android/view/ViewRootImpl.java45
-rw-r--r--core/java/android/view/WindowInsets.java7
-rw-r--r--core/java/android/view/autofill/AutofillManager.java66
-rw-r--r--core/java/android/view/inputmethod/CursorAnchorInfo.java104
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java108
-rw-r--r--core/java/android/view/translation/UiTranslationManager.java40
-rw-r--r--core/java/android/widget/TextView.java19
-rw-r--r--core/java/android/window/OnBackInvokedDispatcher.java20
-rw-r--r--core/java/android/window/PictureInPictureSurfaceTransaction.java30
-rw-r--r--core/java/android/window/SurfaceSyncer.java31
-rw-r--r--core/java/android/window/WindowOnBackInvokedDispatcher.java18
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java94
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java105
-rw-r--r--core/java/com/android/internal/app/chooser/DisplayResolveInfo.java5
-rw-r--r--core/java/com/android/internal/app/chooser/SelectableTargetInfo.java3
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java5
-rw-r--r--core/java/com/android/internal/inputmethod/InputBindResult.java31
-rw-r--r--core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java3
-rw-r--r--core/java/com/android/internal/jank/FrameTracker.java58
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java3
-rw-r--r--core/java/com/android/internal/os/MobileRadioPowerCalculator.java11
-rw-r--r--core/java/com/android/internal/policy/DecorView.java8
-rw-r--r--core/java/com/android/internal/policy/TransitionAnimation.java25
-rw-r--r--core/java/com/android/internal/view/IInputMethodClient.aidl1
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl3
-rw-r--r--core/java/com/android/internal/widget/CachingIconView.java5
-rw-r--r--core/java/com/android/internal/widget/LocalImageResolver.java43
-rw-r--r--core/jni/OWNERS1
-rw-r--r--core/jni/android_hardware_input_InputApplicationHandle.cpp5
-rw-r--r--core/jni/android_hardware_input_InputWindowHandle.cpp7
-rw-r--r--core/jni/android_os_Trace.cpp26
-rw-r--r--core/proto/android/app/activitymanager.proto2
-rw-r--r--core/proto/android/server/activitymanagerservice.proto2
-rw-r--r--core/res/AndroidManifest.xml25
-rw-r--r--core/res/res/anim/activity_close_enter_legacy.xml34
-rw-r--r--core/res/res/anim/activity_close_exit_legacy.xml44
-rw-r--r--core/res/res/anim/activity_open_enter_legacy.xml42
-rw-r--r--core/res/res/anim/activity_open_exit_legacy.xml45
-rw-r--r--core/res/res/values-af/strings.xml17
-rw-r--r--core/res/res/values-am/strings.xml17
-rw-r--r--core/res/res/values-ar/strings.xml22
-rw-r--r--core/res/res/values-as/strings.xml16
-rw-r--r--core/res/res/values-az/strings.xml16
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml16
-rw-r--r--core/res/res/values-be/strings.xml17
-rw-r--r--core/res/res/values-bg/strings.xml17
-rw-r--r--core/res/res/values-bn/strings.xml17
-rw-r--r--core/res/res/values-bs/strings.xml18
-rw-r--r--core/res/res/values-ca/strings.xml17
-rw-r--r--core/res/res/values-cs/strings.xml17
-rw-r--r--core/res/res/values-da/strings.xml17
-rw-r--r--core/res/res/values-de/strings.xml16
-rw-r--r--core/res/res/values-el/strings.xml17
-rw-r--r--core/res/res/values-en-rAU/strings.xml16
-rw-r--r--core/res/res/values-en-rCA/strings.xml16
-rw-r--r--core/res/res/values-en-rGB/strings.xml16
-rw-r--r--core/res/res/values-en-rIN/strings.xml16
-rw-r--r--core/res/res/values-en-rXC/strings.xml16
-rw-r--r--core/res/res/values-es-rUS/strings.xml19
-rw-r--r--core/res/res/values-es/strings.xml17
-rw-r--r--core/res/res/values-et/strings.xml17
-rw-r--r--core/res/res/values-eu/strings.xml16
-rw-r--r--core/res/res/values-fa/strings.xml33
-rw-r--r--core/res/res/values-fi/strings.xml17
-rw-r--r--core/res/res/values-fr-rCA/strings.xml17
-rw-r--r--core/res/res/values-fr/strings.xml17
-rw-r--r--core/res/res/values-gl/strings.xml17
-rw-r--r--core/res/res/values-gu/strings.xml16
-rw-r--r--core/res/res/values-hi/strings.xml16
-rw-r--r--core/res/res/values-hr/strings.xml16
-rw-r--r--core/res/res/values-hu/strings.xml17
-rw-r--r--core/res/res/values-hy/strings.xml17
-rw-r--r--core/res/res/values-in/strings.xml17
-rw-r--r--core/res/res/values-is/strings.xml17
-rw-r--r--core/res/res/values-it/strings.xml17
-rw-r--r--core/res/res/values-iw/strings.xml16
-rw-r--r--core/res/res/values-ja/strings.xml17
-rw-r--r--core/res/res/values-ka/strings.xml17
-rw-r--r--core/res/res/values-kk/strings.xml17
-rw-r--r--core/res/res/values-km/strings.xml17
-rw-r--r--core/res/res/values-kn/strings.xml16
-rw-r--r--core/res/res/values-ko/strings.xml17
-rw-r--r--core/res/res/values-ky/strings.xml17
-rw-r--r--core/res/res/values-lo/strings.xml17
-rw-r--r--core/res/res/values-lt/strings.xml17
-rw-r--r--core/res/res/values-lv/strings.xml17
-rw-r--r--core/res/res/values-mk/strings.xml16
-rw-r--r--core/res/res/values-ml/strings.xml16
-rw-r--r--core/res/res/values-mn/strings.xml16
-rw-r--r--core/res/res/values-mr/strings.xml17
-rw-r--r--core/res/res/values-ms/strings.xml16
-rw-r--r--core/res/res/values-my/strings.xml17
-rw-r--r--core/res/res/values-nb/strings.xml17
-rw-r--r--core/res/res/values-ne/strings.xml17
-rw-r--r--core/res/res/values-nl/strings.xml19
-rw-r--r--core/res/res/values-or/strings.xml17
-rw-r--r--core/res/res/values-pa/strings.xml17
-rw-r--r--core/res/res/values-pl/strings.xml17
-rw-r--r--core/res/res/values-pt-rBR/strings.xml19
-rw-r--r--core/res/res/values-pt-rPT/strings.xml17
-rw-r--r--core/res/res/values-pt/strings.xml19
-rw-r--r--core/res/res/values-ro/strings.xml16
-rw-r--r--core/res/res/values-ru/strings.xml34
-rw-r--r--core/res/res/values-si/strings.xml17
-rw-r--r--core/res/res/values-sk/strings.xml17
-rw-r--r--core/res/res/values-sl/strings.xml17
-rw-r--r--core/res/res/values-sq/strings.xml17
-rw-r--r--core/res/res/values-sr/strings.xml16
-rw-r--r--core/res/res/values-sv/strings.xml17
-rw-r--r--core/res/res/values-sw/strings.xml17
-rw-r--r--core/res/res/values-ta/strings.xml17
-rw-r--r--core/res/res/values-te/strings.xml16
-rw-r--r--core/res/res/values-th/strings.xml16
-rw-r--r--core/res/res/values-tl/strings.xml16
-rw-r--r--core/res/res/values-tr/strings.xml17
-rw-r--r--core/res/res/values-uk/strings.xml17
-rw-r--r--core/res/res/values-ur/strings.xml17
-rw-r--r--core/res/res/values-uz/strings.xml17
-rw-r--r--core/res/res/values-vi/strings.xml17
-rw-r--r--core/res/res/values-zh-rCN/strings.xml17
-rw-r--r--core/res/res/values-zh-rHK/strings.xml17
-rw-r--r--core/res/res/values-zh-rTW/strings.xml17
-rw-r--r--core/res/res/values-zu/strings.xml16
-rw-r--r--core/res/res/values/colors_car.xml4
-rw-r--r--core/res/res/values/config.xml32
-rw-r--r--core/res/res/values/strings.xml8
-rw-r--r--core/res/res/values/symbols.xml9
-rw-r--r--core/tests/coretests/src/android/companion/virtual/audio/VirtualAudioSessionTest.java4
-rw-r--r--core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java142
-rw-r--r--core/tests/coretests/src/android/print/IPrintManagerParametersTest.java14
-rw-r--r--core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java63
-rw-r--r--core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java134
-rw-r--r--core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java4
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java3
-rw-r--r--core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java50
-rw-r--r--data/etc/privapp-permissions-platform.xml3
-rw-r--r--identity/java/android/security/identity/CredstoreIdentityCredentialStore.java13
-rw-r--r--keystore/java/android/security/KeyStoreException.java153
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java58
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java11
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/Android.bp6
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java77
-rw-r--r--libs/WindowManager/Shell/Android.bp5
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt48
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java23
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java48
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java28
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java28
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitDecorManager.java182
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java32
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java243
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java19
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java54
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java10
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreenShellTransit.kt44
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreenShellTransit.kt42
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt19
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreenShellTransit.kt42
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest_ShellTransit.kt64
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTestShellTransit.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt49
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java36
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java19
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java42
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp10
-rw-r--r--location/java/android/location/OWNERS5
-rw-r--r--media/jni/soundpool/SoundPool.cpp5
-rw-r--r--media/jni/soundpool/SoundPool.h2
-rw-r--r--media/jni/soundpool/StreamManager.cpp4
-rw-r--r--media/jni/soundpool/StreamManager.h2
-rw-r--r--media/jni/soundpool/android_media_SoundPool.cpp2
-rw-r--r--media/jni/soundpool/tests/soundpool_stress.cpp2
-rw-r--r--native/android/activity_manager.cpp3
-rw-r--r--native/android/libandroid_net.map.txt8
-rw-r--r--native/android/net.c4
-rw-r--r--packages/CompanionDeviceManager/res/values-as/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-az/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-bs/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-de/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rAU/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rCA/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rGB/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rIN/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-gu/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-hi/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-hr/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-kn/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-mk/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-ml/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-mn/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-ms/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-ro/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-sr/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-te/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-th/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-tl/strings.xml9
-rw-r--r--packages/CompanionDeviceManager/res/values-zu/strings.xml9
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java81
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags2
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java209
-rw-r--r--packages/PrintSpooler/res/values-nl/strings.xml2
-rw-r--r--packages/SettingsLib/res/drawable/ic_qr_code_scanner.xml23
-rw-r--r--packages/SettingsLib/res/layout/qrcode_scan_mode_activity.xml30
-rw-r--r--packages/SettingsLib/res/layout/qrcode_scanner_fragment.xml101
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml27
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml38
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml27
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-en-rCA/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml27
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml27
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml27
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml27
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml27
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml18
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml18
-rw-r--r--packages/SettingsLib/res/values/colors.xml6
-rw-r--r--packages/SettingsLib/res/values/dimens.xml6
-rw-r--r--packages/SettingsLib/res/values/strings.xml9
-rw-r--r--packages/SettingsLib/res/values/styles.xml12
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java27
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java37
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/qrcode/QrCamera.java478
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/qrcode/QrDecorateView.java140
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/qrcode/QrYuvLuminanceSource.java72
-rw-r--r--packages/Shell/AndroidManifest.xml9
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt407
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ViewRootSync.kt6
-rw-r--r--packages/SystemUI/res/drawable/ic_broadcast_code_eye.xml26
-rw-r--r--packages/SystemUI/res/drawable/ic_mic_off.xml10
-rw-r--r--packages/SystemUI/res/drawable/ic_videocam_off.xml13
-rw-r--r--packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml9
-rw-r--r--packages/SystemUI/res/layout/dream_overlay_complication_weather.xml8
-rw-r--r--packages/SystemUI/res/layout/media_output_broadcast_area.xml140
-rw-r--r--packages/SystemUI/res/layout/media_output_broadcast_update_dialog.xml29
-rw-r--r--packages/SystemUI/res/layout/media_output_dialog.xml7
-rw-r--r--packages/SystemUI/res/values-television/config.xml4
-rw-r--r--packages/SystemUI/res/values-television/dimens.xml3
-rw-r--r--packages/SystemUI/res/values/dimens.xml14
-rw-r--r--packages/SystemUI/res/values/drawables.xml26
-rw-r--r--packages/SystemUI/res/values/strings.xml60
-rw-r--r--packages/SystemUI/res/values/styles.xml76
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java31
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java26
-rw-r--r--packages/SystemUI/src/com/android/keyguard/AnimatableClockView.kt33
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java34
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt68
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerFactory.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayEvent.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java115
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaData.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt90
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt207
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java249
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java76
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java109
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java199
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java41
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt482
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayEventTest.java93
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java94
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt37
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt174
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt33
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt167
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaSessionBasedFilterTest.kt31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java358
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt40
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java54
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java20
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java11
-rw-r--r--services/autofill/java/com/android/server/autofill/ViewState.java6
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java31
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java9
-rw-r--r--services/companion/java/com/android/server/companion/virtual/audio/AudioPlaybackDetector.java6
-rw-r--r--services/companion/java/com/android/server/companion/virtual/audio/AudioRecordingDetector.java6
-rw-r--r--services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java35
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java98
-rw-r--r--services/core/java/com/android/server/AlarmManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/BootReceiver.java11
-rw-r--r--services/core/java/com/android/server/PinnerService.java4
-rw-r--r--services/core/java/com/android/server/SmartStorageMaintIdler.java6
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java92
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java10
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java4
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java4
-rw-r--r--services/core/java/com/android/server/am/AppBatteryTracker.java118
-rw-r--r--services/core/java/com/android/server/am/AppRestrictionController.java82
-rw-r--r--services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java3
-rw-r--r--services/core/java/com/android/server/am/BaseAppStatePolicy.java6
-rw-r--r--services/core/java/com/android/server/am/BaseAppStateTimeSlotEventsTracker.java13
-rw-r--r--services/core/java/com/android/server/am/BaseErrorDialog.java37
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java23
-rw-r--r--services/core/java/com/android/server/am/DataConnectionStats.java3
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java139
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java48
-rw-r--r--services/core/java/com/android/server/am/UidObserverController.java23
-rw-r--r--services/core/java/com/android/server/am/UidRecord.java50
-rw-r--r--services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java16
-rw-r--r--services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java5
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java6
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricSensor.java18
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java90
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java3
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java57
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java2
-rw-r--r--services/core/java/com/android/server/display/OWNERS1
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java36
-rw-r--r--services/core/java/com/android/server/dreams/DreamUiEventLogger.java62
-rw-r--r--services/core/java/com/android/server/dreams/DreamUiEventLoggerImpl.java50
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java1
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java5
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecNetwork.java66
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java4
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodBindingController.java2
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java196
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssLocationProvider.java14
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java32
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java119
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java1
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java3
-rw-r--r--services/core/java/com/android/server/pm/AppsFilterImpl.java (renamed from services/core/java/com/android/server/pm/AppsFilter.java)1012
-rw-r--r--services/core/java/com/android/server/pm/AppsFilterSnapshot.java86
-rw-r--r--services/core/java/com/android/server/pm/BroadcastHelper.java11
-rw-r--r--services/core/java/com/android/server/pm/Computer.java26
-rw-r--r--services/core/java/com/android/server/pm/ComputerEngine.java110
-rw-r--r--services/core/java/com/android/server/pm/DeletePackageHelper.java1
-rw-r--r--services/core/java/com/android/server/pm/DistractingPackageHelper.java198
-rw-r--r--services/core/java/com/android/server/pm/DumpHelper.java316
-rw-r--r--services/core/java/com/android/server/pm/IPackageManagerBase.java2
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java2
-rw-r--r--services/core/java/com/android/server/pm/Installer.java17
-rw-r--r--services/core/java/com/android/server/pm/IntentResolverInterceptor.java2
-rw-r--r--services/core/java/com/android/server/pm/KnownPackages.java213
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java159
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerInternalBase.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java263
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceInjector.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java154
-rw-r--r--services/core/java/com/android/server/pm/RemovePackageHelper.java17
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java4
-rw-r--r--services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java6
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java110
-rw-r--r--services/core/java/com/android/server/pm/StorageEventHelper.java35
-rw-r--r--services/core/java/com/android/server/pm/SuspendPackageHelper.java18
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java19
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java11
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java25
-rw-r--r--services/core/java/com/android/server/pm/resolution/ComponentResolver.java116
-rw-r--r--services/core/java/com/android/server/pm/resolution/ComponentResolverApi.java19
-rw-r--r--services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java119
-rw-r--r--services/core/java/com/android/server/pm/resolution/ComponentResolverLocked.java49
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java52
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java12
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java14
-rw-r--r--services/core/java/com/android/server/power/Notifier.java9
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java18
-rw-r--r--services/core/java/com/android/server/power/hint/HintManagerService.java4
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java22
-rw-r--r--services/core/java/com/android/server/utils/WatchedArrayList.java7
-rw-r--r--services/core/java/com/android/server/utils/WatchedArraySet.java12
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java20
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseSetArray.java177
-rw-r--r--services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java2
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationSettings.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityClientController.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityInterceptorCallback.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java18
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartInterceptor.java14
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java43
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java84
-rw-r--r--services/core/java/com/android/server/wm/DisplayFrames.java13
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java12
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowSettings.java3
-rw-r--r--services/core/java/com/android/server/wm/FactoryErrorDialog.java3
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java4
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java2
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimationRunner.java84
-rw-r--r--services/core/java/com/android/server/wm/Task.java32
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java2
-rw-r--r--services/core/java/com/android/server/wm/Transition.java23
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java1
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java23
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java138
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java1
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java1
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java108
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java46
-rw-r--r--services/print/java/com/android/server/print/PrintManagerService.java27
-rw-r--r--services/print/java/com/android/server/print/UserState.java10
-rw-r--r--services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java2
-rw-r--r--services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt7
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java255
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java172
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java8
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt195
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt13
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt141
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt196
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt127
-rw-r--r--services/tests/servicestests/src/com/android/server/appwidget/OWNERS1
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java44
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java34
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java28
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java170
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java68
-rw-r--r--services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java (renamed from services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java)215
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java166
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/utils/WatcherTest.java61
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java81
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java45
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java2
-rw-r--r--services/translation/java/com/android/server/translation/TranslationManagerService.java12
-rw-r--r--services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java194
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java3
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java18
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java5
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt33
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt41
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt10
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest_ShellTransit.kt60
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest_ShellTransit.kt6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt3
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt8
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest_ShellTransit.kt62
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt9
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt55
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt10
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestShellTransit.kt147
-rw-r--r--tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java5
658 files changed, 14608 insertions, 7516 deletions
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 038ee6501ded..5ec107da8b94 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -231,7 +231,7 @@ droiddoc {
"android.whichdoc offline",
],
compat_config: ":global-compat-config",
- proofread_file: "offline-sdk-docs-proofrerad.txt",
+ proofread_file: "offline-sdk-docs-proofread.txt",
args: framework_docs_only_args + " -offlinemode -title \"Android SDK\"",
static_doc_index_redirect: "docs/docs-preview-index.html",
}
@@ -248,7 +248,7 @@ droiddoc {
hdf: [
"android.whichdoc offline",
],
- proofread_file: "offline-sdk-referenceonly-docs-proofrerad.txt",
+ proofread_file: "offline-sdk-referenceonly-docs-proofread.txt",
args: framework_docs_only_args + " -offlinemode -title \"Android SDK\" -referenceonly",
static_doc_index_redirect: "docs/docs-documentation-redirect.html",
static_doc_properties: "docs/source.properties",
@@ -266,7 +266,7 @@ droiddoc {
hdf: [
"android.whichdoc offline",
],
- proofread_file: "offline-system-sdk-referenceonly-docs-proofrerad.txt",
+ proofread_file: "offline-system-sdk-referenceonly-docs-proofread.txt",
args: framework_docs_only_args + " -hide 101 -hide 104 -hide 108" +
" -offlinemode -title \"Android System SDK\" -referenceonly",
static_doc_index_redirect: "docs/docs-documentation-redirect.html",
@@ -283,7 +283,7 @@ droiddoc {
"android.whichdoc online",
"android.hasSamples true",
],
- proofread_file: "online-sdk-docs-proofrerad.txt",
+ proofread_file: "online-sdk-docs-proofread.txt",
args: framework_docs_only_args +
" -toroot / -samplegroup Admin " +
" -samplegroup Background " +
@@ -312,7 +312,7 @@ droiddoc {
"android.whichdoc online",
"android.hasSamples true",
],
- proofread_file: "online-system-api-sdk-docs-proofrerad.txt",
+ proofread_file: "online-system-api-sdk-docs-proofread.txt",
args: framework_docs_only_args +
" -referenceonly " +
" -title \"Android SDK - Including system APIs.\" " +
@@ -347,7 +347,7 @@ droiddoc {
"android.whichdoc online",
"android.hasSamples true",
],
- proofread_file: "ds-docs-proofrerad.txt",
+ proofread_file: "ds-docs-proofread.txt",
args: framework_docs_only_args +
" -toroot / -yamlV2 -metalavaApiSince -samplegroup Admin " +
" -samplegroup Background " +
@@ -458,7 +458,7 @@ droiddoc {
"android.whichdoc online",
"android.hasSamples true",
],
- proofread_file: "online-sdk-dev-docs-proofrerad.txt",
+ proofread_file: "online-sdk-dev-docs-proofread.txt",
args: framework_docs_only_args +
" -toroot / -samplegroup Admin " +
" -samplegroup Background " +
@@ -483,7 +483,7 @@ droiddoc {
srcs: [
":framework-doc-stubs",
],
- proofread_file: "hidden-docs-proofrerad.txt",
+ proofread_file: "hidden-docs-proofread.txt",
args: framework_docs_only_args +
" -referenceonly " +
" -title \"Android SDK - Including hidden APIs.\"",
diff --git a/OWNERS b/OWNERS
index 47d8c83fea03..d4d19365f4d1 100644
--- a/OWNERS
+++ b/OWNERS
@@ -31,5 +31,6 @@ per-file */res*/values*/*.xml = byi@google.com, delphij@google.com
per-file *.bp = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION}
per-file Android.mk = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION}
+per-file framework-jarjar-rules.txt = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION}
per-file TestProtoLibraries.bp = file:platform/platform_testing:/libraries/health/OWNERS
per-file TestProtoLibraries.bp = file:platform/tools/tradefederation:/OWNERS
diff --git a/TRACE_OWNERS b/TRACE_OWNERS
new file mode 100644
index 000000000000..f746a162bc8f
--- /dev/null
+++ b/TRACE_OWNERS
@@ -0,0 +1,5 @@
+# OWNERS of Trace-related files
+primiano@google.com
+timmurray@google.com
+jjaggi@google.com
+jreck@google.com
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index da429af7e351..61424ae0e158 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -270,6 +270,16 @@ public class AlarmManager {
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
public static final long ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS = 185199076L;
+ /**
+ * For apps targeting {@link Build.VERSION_CODES#TIRAMISU} or above, certain kinds of apps can
+ * use {@link Manifest.permission#USE_EXACT_ALARM} to schedule exact alarms.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+ public static final long ENABLE_USE_EXACT_ALARM = 218533173L;
+
@UnsupportedAppUsage
private final IAlarmManager mService;
private final Context mContext;
diff --git a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
index 70d5038945f3..fab5b5fd6933 100644
--- a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
+++ b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
@@ -767,6 +767,10 @@ public class AppStateTrackerImpl implements AppStateTracker {
@Override
public void onUidCachedChanged(int uid, boolean cached) {
}
+
+ @Override
+ public void onUidProcAdjChanged(int uid) {
+ }
}
private final class AppOpsWatcher extends IAppOpsCallback.Stub {
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index a09f39f26eab..f67e8d2baa11 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -1827,30 +1827,9 @@ public class AlarmManagerService extends SystemService {
newAppIds.add(UserHandle.getAppId(uid));
}
}
- final ArraySet<Integer> removed = new ArraySet<>(mExactAlarmCandidates);
- removed.removeAll(newAppIds);
- // This code is only called on package_added and boot. The set {removed} is only expected to
- // be non-empty when a package was updated and it removed the permission from its manifest.
- for (int i = 0; i < removed.size(); i++) {
- final int removedAppId = removed.valueAt(i);
- synchronized (mLock) {
- Slog.i(TAG, "App id " + removedAppId + " lost SCHEDULE_EXACT_ALARM on update");
+ // Some packages may have lost permission to schedule exact alarms on update, their alarms
+ // will be removed while handling CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE after this.
- final Predicate<Alarm> whichAlarms = a -> {
- if (UserHandle.getAppId(a.uid) != removedAppId || a.windowLength != 0) {
- return false;
- }
- if (!isExactAlarmChangeEnabled(a.packageName, UserHandle.getUserId(a.uid))) {
- return false;
- }
- if (hasUseExactAlarmPermission(a.packageName, a.uid)) {
- return false;
- }
- return !isExemptFromExactAlarmPermission(a.uid);
- };
- removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_EXACT_PERMISSION_REVOKED);
- }
- }
// No need to lock. Assignment is always atomic.
mExactAlarmCandidates = Collections.unmodifiableSet(newAppIds);
}
@@ -1910,7 +1889,7 @@ public class AlarmManagerService extends SystemService {
|| !isExactAlarmChangeEnabled(packageName, userId)) {
return;
}
- if (hasUseExactAlarmPermission(packageName, uid)) {
+ if (hasUseExactAlarmInternal(packageName, uid)) {
return;
}
@@ -2533,8 +2512,9 @@ public class AlarmManagerService extends SystemService {
}
@Override
- public boolean hasScheduleExactAlarm(String packageName, int uid) {
- return hasScheduleExactAlarmInternal(packageName, uid);
+ public boolean hasExactAlarmPermission(String packageName, int uid) {
+ return hasScheduleExactAlarmInternal(packageName, uid)
+ || hasUseExactAlarmInternal(packageName, uid);
}
@Override
@@ -2558,21 +2538,19 @@ public class AlarmManagerService extends SystemService {
return appOpMode == AppOpsManager.MODE_ALLOWED;
}
- boolean hasUseExactAlarmPermission(String packageName, int uid) {
- return PermissionChecker.checkPermissionForPreflight(getContext(),
+ boolean hasUseExactAlarmInternal(String packageName, int uid) {
+ return isUseExactAlarmEnabled(packageName, UserHandle.getUserId(uid))
+ && (PermissionChecker.checkPermissionForPreflight(getContext(),
Manifest.permission.USE_EXACT_ALARM, PermissionChecker.PID_UNKNOWN, uid,
- packageName) == PermissionChecker.PERMISSION_GRANTED;
+ packageName) == PermissionChecker.PERMISSION_GRANTED);
}
boolean hasScheduleExactAlarmInternal(String packageName, int uid) {
- if (hasUseExactAlarmPermission(packageName, uid)) {
- return true;
- }
+ final long start = mStatLogger.getTime();
+
// Not using getScheduleExactAlarmState as this can avoid some calls to AppOpsService.
// Not using #mLastOpScheduleExactAlarm as it may contain stale values.
// No locking needed as all internal containers being queried are immutable.
-
- final long start = mStatLogger.getTime();
final boolean hasPermission;
if (!mExactAlarmCandidates.contains(UserHandle.getAppId(uid))) {
hasPermission = false;
@@ -2703,7 +2681,8 @@ public class AlarmManagerService extends SystemService {
lowerQuota = allowWhileIdle;
idleOptions = allowWhileIdle ? mOptsWithFgs.toBundle() : null;
}
- if (needsPermission && !hasScheduleExactAlarmInternal(callingPackage, callingUid)) {
+ if (needsPermission && !hasScheduleExactAlarmInternal(callingPackage, callingUid)
+ && !hasUseExactAlarmInternal(callingPackage, callingUid)) {
if (!isExemptFromExactAlarmPermission(callingUid)) {
final String errorMessage = "Caller " + callingPackage + " needs to hold "
+ Manifest.permission.SCHEDULE_EXACT_ALARM + " to set "
@@ -2768,7 +2747,8 @@ public class AlarmManagerService extends SystemService {
return true;
}
return isExemptFromExactAlarmPermission(packageUid)
- || hasScheduleExactAlarmInternal(packageName, packageUid);
+ || hasScheduleExactAlarmInternal(packageName, packageUid)
+ || hasUseExactAlarmInternal(packageName, packageUid);
}
@Override
@@ -2875,6 +2855,11 @@ public class AlarmManagerService extends SystemService {
packageName, UserHandle.of(userId));
}
+ private static boolean isUseExactAlarmEnabled(String packageName, int userId) {
+ return CompatChanges.isChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM,
+ packageName, UserHandle.of(userId));
+ }
+
@NeverCompile // Avoid size overhead of debugging code.
void dumpImpl(IndentingPrintWriter pw) {
synchronized (mLock) {
@@ -3784,7 +3769,7 @@ public class AlarmManagerService extends SystemService {
if (!isExactAlarmChangeEnabled(changedPackage, userId)) {
continue;
}
- if (hasUseExactAlarmPermission(changedPackage, uid)) {
+ if (hasUseExactAlarmInternal(changedPackage, uid)) {
continue;
}
final int appOpMode;
@@ -3817,8 +3802,9 @@ public class AlarmManagerService extends SystemService {
}
/**
- * Called when an app loses {@link Manifest.permission#SCHEDULE_EXACT_ALARM} to remove alarms
- * that the app is no longer eligible to use.
+ * Called when an app loses the permission to use exact alarms. This will happen when the app
+ * no longer has either {@link Manifest.permission#SCHEDULE_EXACT_ALARM} or
+ * {@link Manifest.permission#USE_EXACT_ALARM}.
*
* This is not expected to get called frequently.
*/
@@ -3828,7 +3814,8 @@ public class AlarmManagerService extends SystemService {
|| !isExactAlarmChangeEnabled(packageName, UserHandle.getUserId(uid))) {
return;
}
- Slog.w(TAG, "Package " + packageName + ", uid " + uid + " lost SCHEDULE_EXACT_ALARM!");
+ Slog.w(TAG, "Package " + packageName + ", uid " + uid
+ + " lost permission to set exact alarms!");
final Predicate<Alarm> whichAlarms = a -> (a.uid == uid && a.packageName.equals(packageName)
&& a.windowLength == 0);
@@ -4764,7 +4751,8 @@ public class AlarmManagerService extends SystemService {
case CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE:
packageName = (String) msg.obj;
uid = msg.arg1;
- if (!hasScheduleExactAlarmInternal(packageName, uid)) {
+ if (!hasScheduleExactAlarmInternal(packageName, uid)
+ && !hasUseExactAlarmInternal(packageName, uid)) {
synchronized (mLock) {
removeExactAlarmsOnPermissionRevokedLocked(uid,
packageName, /*killUid = */false);
@@ -4936,13 +4924,15 @@ public class AlarmManagerService extends SystemService {
mLastOpScheduleExactAlarm.delete(uid);
return;
case Intent.ACTION_PACKAGE_ADDED:
+ mHandler.sendEmptyMessage(AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES);
if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ // Some apps may lose permission to set exact alarms on update.
+ // We need to remove their exact alarms.
final String packageUpdated = intent.getData().getSchemeSpecificPart();
mHandler.obtainMessage(
AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE, uid, -1,
packageUpdated).sendToTarget();
}
- mHandler.sendEmptyMessage(AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES);
return;
case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
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 69189d51614d..b4238c975d98 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -16,7 +16,6 @@
package com.android.server.job;
-import static com.android.server.job.JobSchedulerService.MAX_JOB_CONTEXTS_COUNT;
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
@@ -68,6 +67,8 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -80,6 +81,11 @@ class JobConcurrencyManager {
private static final String TAG = JobSchedulerService.TAG + ".Concurrency";
private static final boolean DEBUG = JobSchedulerService.DEBUG;
+ /** The maximum number of concurrent jobs we'll aim to run at one time. */
+ public static final int STANDARD_CONCURRENCY_LIMIT = 16;
+ /** The maximum number of objects we should retain in memory when not in use. */
+ private static final int MAX_RETAINED_OBJECTS = (int) (1.5 * STANDARD_CONCURRENCY_LIMIT);
+
static final String CONFIG_KEY_PREFIX_CONCURRENCY = "concurrency_";
private static final String KEY_SCREEN_OFF_ADJUSTMENT_DELAY_MS =
CONFIG_KEY_PREFIX_CONCURRENCY + "screen_off_adjustment_delay_ms";
@@ -91,7 +97,7 @@ class JobConcurrencyManager {
@VisibleForTesting
static final String KEY_PKG_CONCURRENCY_LIMIT_REGULAR =
CONFIG_KEY_PREFIX_CONCURRENCY + "pkg_concurrency_limit_regular";
- private static final int DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR = MAX_JOB_CONTEXTS_COUNT / 2;
+ private static final int DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR = STANDARD_CONCURRENCY_LIMIT / 2;
/**
* Set of possible execution types that a job can have. The actual type(s) of a job are based
@@ -267,13 +273,47 @@ class JobConcurrencyManager {
)
);
+ /**
+ * Comparator to sort the determination lists, putting the ContextAssignments that we most
+ * prefer to use at the end of the list.
+ */
+ private static final Comparator<ContextAssignment> sDeterminationComparator = (ca1, ca2) -> {
+ if (ca1 == ca2) {
+ return 0;
+ }
+ final JobStatus js1 = ca1.context.getRunningJobLocked();
+ final JobStatus js2 = ca2.context.getRunningJobLocked();
+ // Prefer using an empty context over one with a running job.
+ if (js1 == null) {
+ if (js2 == null) {
+ return 0;
+ }
+ return 1;
+ } else if (js2 == null) {
+ return -1;
+ }
+ // We would prefer to replace bg jobs over TOP jobs.
+ if (js1.lastEvaluatedBias == JobInfo.BIAS_TOP_APP) {
+ if (js2.lastEvaluatedBias != JobInfo.BIAS_TOP_APP) {
+ return -1;
+ }
+ } else if (js2.lastEvaluatedBias == JobInfo.BIAS_TOP_APP) {
+ return 1;
+ }
+ // Prefer replacing the job that has been running the longest.
+ return Long.compare(
+ ca2.context.getExecutionStartTimeElapsed(),
+ ca1.context.getExecutionStartTimeElapsed());
+ };
+
+ // We reuse the lists to avoid GC churn.
private final ArraySet<ContextAssignment> mRecycledChanged = new ArraySet<>();
private final ArraySet<ContextAssignment> mRecycledIdle = new ArraySet<>();
- private final ArraySet<ContextAssignment> mRecycledPreferredUidOnly = new ArraySet<>();
- private final ArraySet<ContextAssignment> mRecycledStoppable = new ArraySet<>();
+ private final ArrayList<ContextAssignment> mRecycledPreferredUidOnly = new ArrayList<>();
+ private final ArrayList<ContextAssignment> mRecycledStoppable = new ArrayList<>();
private final Pools.Pool<ContextAssignment> mContextAssignmentPool =
- new Pools.SimplePool<>(MAX_JOB_CONTEXTS_COUNT);
+ new Pools.SimplePool<>(MAX_RETAINED_OBJECTS);
/**
* Set of JobServiceContexts that are actively running jobs.
@@ -281,14 +321,16 @@ class JobConcurrencyManager {
final List<JobServiceContext> mActiveServices = new ArrayList<>();
/** Set of JobServiceContexts that aren't currently running any jobs. */
- final ArraySet<JobServiceContext> mIdleContexts = new ArraySet<>();
+ private final ArraySet<JobServiceContext> mIdleContexts = new ArraySet<>();
+
+ private int mNumDroppedContexts = 0;
private final ArraySet<JobStatus> mRunningJobs = new ArraySet<>();
private final WorkCountTracker mWorkCountTracker = new WorkCountTracker();
private final Pools.Pool<PackageStats> mPkgStatsPool =
- new Pools.SimplePool<>(MAX_JOB_CONTEXTS_COUNT);
+ new Pools.SimplePool<>(MAX_RETAINED_OBJECTS);
private final SparseArrayMap<String, PackageStats> mActivePkgStats = new SparseArrayMap<>();
@@ -370,7 +412,7 @@ class JobConcurrencyManager {
void onThirdPartyAppsCanStart() {
final IBatteryStats batteryStats = IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME));
- for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
+ for (int i = 0; i < STANDARD_CONCURRENCY_LIMIT; i++) {
mIdleContexts.add(
new JobServiceContext(mService, this, batteryStats,
mService.mJobPackageTracker, mContext.getMainLooper()));
@@ -570,14 +612,19 @@ class JobConcurrencyManager {
Slog.d(TAG, printPendingQueueLocked());
}
+ if (mService.getPendingJobQueue().size() == 0) {
+ // Nothing to do.
+ return;
+ }
+
final PendingJobQueue pendingJobQueue = mService.getPendingJobQueue();
final List<JobServiceContext> activeServices = mActiveServices;
// To avoid GC churn, we recycle the arrays.
final ArraySet<ContextAssignment> changed = mRecycledChanged;
final ArraySet<ContextAssignment> idle = mRecycledIdle;
- final ArraySet<ContextAssignment> preferredUidOnly = mRecycledPreferredUidOnly;
- final ArraySet<ContextAssignment> stoppable = mRecycledStoppable;
+ final ArrayList<ContextAssignment> preferredUidOnly = mRecycledPreferredUidOnly;
+ final ArrayList<ContextAssignment> stoppable = mRecycledStoppable;
updateCounterConfigLocked();
// Reset everything since we'll re-evaluate the current state.
@@ -612,13 +659,15 @@ class JobConcurrencyManager {
preferredUidOnly.add(assignment);
}
}
- for (int i = numRunningJobs; i < MAX_JOB_CONTEXTS_COUNT; ++i) {
+ preferredUidOnly.sort(sDeterminationComparator);
+ stoppable.sort(sDeterminationComparator);
+ for (int i = numRunningJobs; i < STANDARD_CONCURRENCY_LIMIT; ++i) {
final JobServiceContext jsc;
final int numIdleContexts = mIdleContexts.size();
if (numIdleContexts > 0) {
jsc = mIdleContexts.removeAt(numIdleContexts - 1);
} else {
- Slog.wtf(TAG, "Had fewer than " + MAX_JOB_CONTEXTS_COUNT + " in existence");
+ Slog.wtf(TAG, "Had fewer than " + STANDARD_CONCURRENCY_LIMIT + " in existence");
jsc = createNewJobServiceContext();
}
@@ -638,6 +687,7 @@ class JobConcurrencyManager {
JobStatus nextPending;
pendingJobQueue.resetIterator();
+ int projectedRunningCount = numRunningJobs;
while ((nextPending = pendingJobQueue.next()) != null) {
if (mRunningJobs.contains(nextPending)) {
continue;
@@ -651,6 +701,9 @@ class JobConcurrencyManager {
ContextAssignment selectedContext = null;
final int allWorkTypes = getJobWorkTypes(nextPending);
final boolean pkgConcurrencyOkay = !isPkgConcurrencyLimitedLocked(nextPending);
+ final boolean isTopEj = nextPending.shouldTreatAsExpeditedJob()
+ && nextPending.lastEvaluatedBias == JobInfo.BIAS_TOP_APP;
+ final boolean isInOverage = projectedRunningCount > STANDARD_CONCURRENCY_LIMIT;
boolean startingJob = false;
if (idle.size() > 0) {
final int idx = idle.size() - 1;
@@ -668,14 +721,36 @@ class JobConcurrencyManager {
assignment.newWorkType = workType;
}
}
- if (selectedContext == null) {
+ if (selectedContext == null && stoppable.size() > 0) {
+ int topEjCount = 0;
+ for (int r = mRunningJobs.size() - 1; r >= 0; --r) {
+ JobStatus js = mRunningJobs.valueAt(r);
+ if (js.startedAsExpeditedJob && js.lastEvaluatedBias == JobInfo.BIAS_TOP_APP) {
+ topEjCount++;
+ }
+ }
for (int s = stoppable.size() - 1; s >= 0; --s) {
- ContextAssignment assignment = stoppable.valueAt(s);
- JobStatus runningJob = assignment.context.getRunningJobLocked();
- // Maybe stop the job if it has had its day in the sun. Don't let a different
- // app preempt jobs started for TOP apps though.
- if (runningJob.lastEvaluatedBias < JobInfo.BIAS_TOP_APP
- && assignment.shouldStopJobReason != null) {
+ final ContextAssignment assignment = stoppable.get(s);
+ final JobStatus runningJob = assignment.context.getRunningJobLocked();
+ // Maybe stop the job if it has had its day in the sun. Only allow replacing
+ // for one of the following conditions:
+ // 1. We're putting in the current TOP app's EJ
+ // 2. There aren't too many jobs running AND the current job started when the
+ // app was in the background
+ // 3. There aren't too many jobs running AND the current job started when the
+ // app was on TOP, but the app has since left TOP
+ // 4. There aren't too many jobs running AND the current job started when the
+ // app was on TOP, the app is still TOP, but there are too many TOP+EJs
+ // running (because we don't want them to starve out other apps and the
+ // current job has already run for the minimum guaranteed time).
+ boolean canReplace = isTopEj; // Case 1
+ if (!canReplace && !isInOverage) {
+ final int currentJobBias = mService.evaluateJobBiasLocked(runningJob);
+ canReplace = runningJob.lastEvaluatedBias < JobInfo.BIAS_TOP_APP // Case 2
+ || currentJobBias < JobInfo.BIAS_TOP_APP // Case 3
+ || topEjCount > .5 * mWorkTypeConfig.getMaxTotal(); // Case 4
+ }
+ if (canReplace) {
int replaceWorkType = mWorkCountTracker.canJobStart(allWorkTypes,
assignment.context.getRunningJobWorkType());
if (replaceWorkType != WORK_TYPE_NONE) {
@@ -685,7 +760,7 @@ class JobConcurrencyManager {
assignment.preemptReason = assignment.shouldStopJobReason;
assignment.preemptReasonCode = JobParameters.STOP_REASON_DEVICE_STATE;
selectedContext = assignment;
- stoppable.removeAt(s);
+ stoppable.remove(s);
assignment.newJob = nextPending;
assignment.newWorkType = replaceWorkType;
break;
@@ -693,10 +768,10 @@ class JobConcurrencyManager {
}
}
}
- if (selectedContext == null) {
+ if (selectedContext == null && (!isInOverage || isTopEj)) {
int lowestBiasSeen = Integer.MAX_VALUE;
for (int p = preferredUidOnly.size() - 1; p >= 0; --p) {
- final ContextAssignment assignment = preferredUidOnly.valueAt(p);
+ final ContextAssignment assignment = preferredUidOnly.get(p);
final JobStatus runningJob = assignment.context.getRunningJobLocked();
if (runningJob.getUid() != nextPending.getUid()) {
continue;
@@ -722,10 +797,43 @@ class JobConcurrencyManager {
preferredUidOnly.remove(selectedContext);
}
}
+ // Make sure to run EJs for the TOP app immediately.
+ if (isTopEj) {
+ if (selectedContext != null
+ && selectedContext.context.getRunningJobLocked() != null) {
+ // We're "replacing" a currently running job, but we want TOP EJs to start
+ // immediately, so we'll start the EJ on a fresh available context and
+ // stop this currently running job to replace in two steps.
+ changed.add(selectedContext);
+ projectedRunningCount--;
+ selectedContext.newJob = null;
+ selectedContext.newWorkType = WORK_TYPE_NONE;
+ selectedContext = null;
+ }
+ if (selectedContext == null) {
+ selectedContext = mContextAssignmentPool.acquire();
+ if (selectedContext == null) {
+ selectedContext = new ContextAssignment();
+ }
+ selectedContext.context = mIdleContexts.size() > 0
+ ? mIdleContexts.removeAt(mIdleContexts.size() - 1)
+ : createNewJobServiceContext();
+ selectedContext.newJob = nextPending;
+ final int workType = mWorkCountTracker.canJobStart(allWorkTypes);
+ selectedContext.newWorkType =
+ (workType != WORK_TYPE_NONE) ? workType : WORK_TYPE_TOP;
+ }
+ }
final PackageStats packageStats = getPkgStatsLocked(
nextPending.getSourceUserId(), nextPending.getSourcePackageName());
if (selectedContext != null) {
changed.add(selectedContext);
+ if (selectedContext.context.getRunningJobLocked() != null) {
+ projectedRunningCount--;
+ }
+ if (selectedContext.newJob != null) {
+ projectedRunningCount++;
+ }
packageStats.adjustStagedCount(true, nextPending.shouldTreatAsExpeditedJob());
}
if (startingJob) {
@@ -750,7 +858,7 @@ class JobConcurrencyManager {
if (DEBUG) {
Slog.d(TAG, "preempting job: " + js);
}
- // preferredUid will be set to uid of currently running job.
+ // preferredUid will be set to uid of currently running job, if appropriate.
assignment.context.cancelExecutingJobLocked(
assignment.preemptReasonCode,
JobParameters.INTERNAL_STOP_REASON_PREEMPT, assignment.preemptReason);
@@ -767,15 +875,12 @@ class JobConcurrencyManager {
mContextAssignmentPool.release(assignment);
}
for (int s = stoppable.size() - 1; s >= 0; --s) {
- final ContextAssignment assignment = stoppable.valueAt(s);
- // The preferred UID is set when we cancel with PREEMPT reason, but don't preserve the
- // UID for any stoppable contexts since we want to open the context up to any/all apps.
- assignment.context.clearPreferredUid();
+ final ContextAssignment assignment = stoppable.get(s);
assignment.clear();
mContextAssignmentPool.release(assignment);
}
for (int p = preferredUidOnly.size() - 1; p >= 0; --p) {
- final ContextAssignment assignment = preferredUidOnly.valueAt(p);
+ final ContextAssignment assignment = preferredUidOnly.get(p);
assignment.clear();
mContextAssignmentPool.release(assignment);
}
@@ -795,6 +900,21 @@ class JobConcurrencyManager {
}
@GuardedBy("mLock")
+ void onUidBiasChangedLocked(int prevBias, int newBias) {
+ if (prevBias != JobInfo.BIAS_TOP_APP && newBias != JobInfo.BIAS_TOP_APP) {
+ // TOP app didn't change. Nothing to do.
+ return;
+ }
+ if (mService.getPendingJobQueue().size() == 0) {
+ // Nothing waiting for the top app to leave. Nothing to do.
+ return;
+ }
+ // Don't stop the TOP jobs directly. Instead, see if they would be replaced by some
+ // pending job (there may not always be something to replace them).
+ assignJobsToContextsLocked();
+ }
+
+ @GuardedBy("mLock")
boolean stopJobOnServiceContextLocked(JobStatus job,
@JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
if (!mRunningJobs.contains(job)) {
@@ -998,7 +1118,13 @@ class JobConcurrencyManager {
mWorkCountTracker.onJobFinished(workType);
mRunningJobs.remove(jobStatus);
mActiveServices.remove(worker);
- mIdleContexts.add(worker);
+ if (mIdleContexts.size() < MAX_RETAINED_OBJECTS) {
+ // Don't need to save all new contexts, but keep some extra around in case we need
+ // extras for another TOP+EJ overage.
+ mIdleContexts.add(worker);
+ } else {
+ mNumDroppedContexts++;
+ }
final PackageStats packageStats =
mActivePkgStats.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
if (packageStats == null) {
@@ -1011,6 +1137,14 @@ class JobConcurrencyManager {
}
}
+ if (mActiveServices.size() >= STANDARD_CONCURRENCY_LIMIT) {
+ worker.clearPreferredUid();
+ // We're over the limit (because the TOP app scheduled a lot of EJs). Don't start
+ // running anything new until we get back below the limit.
+ noteConcurrency();
+ return;
+ }
+
final PendingJobQueue pendingJobQueue = mService.getPendingJobQueue();
if (worker.getPreferredUid() != JobServiceContext.NO_PREFERRED_UID) {
updateCounterConfigLocked();
@@ -1202,6 +1336,18 @@ class JobConcurrencyManager {
}
} else if (mWorkCountTracker.getPendingJobCount(WORK_TYPE_EJ) > 0) {
return "blocking " + workTypeToString(WORK_TYPE_EJ) + " queue";
+ } else if (js.startedAsExpeditedJob && js.lastEvaluatedBias == JobInfo.BIAS_TOP_APP) {
+ // Try not to let TOP + EJ starve out other apps.
+ int topEjCount = 0;
+ for (int r = mRunningJobs.size() - 1; r >= 0; --r) {
+ JobStatus j = mRunningJobs.valueAt(r);
+ if (j.startedAsExpeditedJob && j.lastEvaluatedBias == JobInfo.BIAS_TOP_APP) {
+ topEjCount++;
+ }
+ }
+ if (topEjCount > .5 * mWorkTypeConfig.getMaxTotal()) {
+ return "prevent top EJ dominance";
+ }
}
// No other pending EJs. Return null so we don't let regular jobs preempt an EJ.
return null;
@@ -1275,12 +1421,12 @@ class JobConcurrencyManager {
return s.toString();
}
- private static String printAssignments(String header, ArraySet<ContextAssignment>... list) {
+ private static String printAssignments(String header, Collection<ContextAssignment>... list) {
final StringBuilder s = new StringBuilder(header + ": ");
for (int l = 0; l < list.length; ++l) {
- ArraySet<ContextAssignment> assignments = list[l];
- for (int c = 0; c < assignments.size(); ++c) {
- final ContextAssignment assignment = assignments.valueAt(c);
+ final Collection<ContextAssignment> assignments = list[l];
+ int c = 0;
+ for (final ContextAssignment assignment : assignments) {
final JobStatus job = assignment.newJob == null
? assignment.context.getRunningJobLocked() : assignment.newJob;
@@ -1294,6 +1440,7 @@ class JobConcurrencyManager {
s.append(job.getJobId()).append("/").append(job.getUid());
}
s.append(")");
+ c++;
}
}
return s.toString();
@@ -1317,10 +1464,10 @@ class JobConcurrencyManager {
CONFIG_LIMITS_SCREEN_OFF.low.update(properties);
CONFIG_LIMITS_SCREEN_OFF.critical.update(properties);
- // Package concurrency limits must in the range [1, MAX_JOB_CONTEXTS_COUNT].
- mPkgConcurrencyLimitEj = Math.max(1, Math.min(MAX_JOB_CONTEXTS_COUNT,
+ // Package concurrency limits must in the range [1, STANDARD_CONCURRENCY_LIMIT].
+ mPkgConcurrencyLimitEj = Math.max(1, Math.min(STANDARD_CONCURRENCY_LIMIT,
properties.getInt(KEY_PKG_CONCURRENCY_LIMIT_EJ, DEFAULT_PKG_CONCURRENCY_LIMIT_EJ)));
- mPkgConcurrencyLimitRegular = Math.max(1, Math.min(MAX_JOB_CONTEXTS_COUNT,
+ mPkgConcurrencyLimitRegular = Math.max(1, Math.min(STANDARD_CONCURRENCY_LIMIT,
properties.getInt(
KEY_PKG_CONCURRENCY_LIMIT_REGULAR, DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR)));
}
@@ -1448,6 +1595,13 @@ class JobConcurrencyManager {
jsc.dumpLocked(pw, nowElapsed);
}
pw.decreaseIndent();
+
+ if (mNumDroppedContexts > 0) {
+ pw.println();
+ pw.print("Dropped ");
+ pw.print(mNumDroppedContexts);
+ pw.println(" contexts");
+ }
}
public void dumpProtoLocked(ProtoOutputStream proto, long tag, long now, long nowRealtime) {
@@ -1556,7 +1710,7 @@ class JobConcurrencyManager {
WorkTypeConfig(@NonNull String configIdentifier, int defaultMaxTotal,
List<Pair<Integer, Integer>> defaultMin, List<Pair<Integer, Integer>> defaultMax) {
mConfigIdentifier = configIdentifier;
- mDefaultMaxTotal = mMaxTotal = Math.min(defaultMaxTotal, MAX_JOB_CONTEXTS_COUNT);
+ mDefaultMaxTotal = mMaxTotal = Math.min(defaultMaxTotal, STANDARD_CONCURRENCY_LIMIT);
int numReserved = 0;
for (int i = defaultMin.size() - 1; i >= 0; --i) {
mDefaultMinReservedSlots.put(defaultMin.get(i).first, defaultMin.get(i).second);
@@ -1577,8 +1731,8 @@ class JobConcurrencyManager {
}
void update(@NonNull DeviceConfig.Properties properties) {
- // Ensure total in the range [1, MAX_JOB_CONTEXTS_COUNT].
- mMaxTotal = Math.max(1, Math.min(MAX_JOB_CONTEXTS_COUNT,
+ // Ensure total in the range [1, STANDARD_CONCURRENCY_LIMIT].
+ mMaxTotal = Math.max(1, Math.min(STANDARD_CONCURRENCY_LIMIT,
properties.getInt(KEY_PREFIX_MAX_TOTAL + mConfigIdentifier, mDefaultMaxTotal)));
mMaxAllowedSlots.clear();
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 1f5c46d3aeb0..b25832c7d521 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -159,8 +159,6 @@ public class JobSchedulerService extends com.android.server.SystemService
public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final boolean DEBUG_STANDBY = DEBUG || false;
- /** The maximum number of concurrent jobs we run at one time. */
- static final int MAX_JOB_CONTEXTS_COUNT = 16;
/** The maximum number of jobs that we allow an app to schedule */
private static final int MAX_JOBS_PER_APP = 150;
/** The number of the most recently completed jobs to keep track of for debugging purposes. */
@@ -1009,6 +1007,9 @@ public class JobSchedulerService extends com.android.server.SystemService
@Override public void onUidCachedChanged(int uid, boolean cached) {
}
+
+ @Override public void onUidProcAdjChanged(int uid) {
+ }
};
public Context getTestableContext() {
@@ -1420,6 +1421,7 @@ public class JobSchedulerService extends com.android.server.SystemService
for (int c = 0; c < mControllers.size(); ++c) {
mControllers.get(c).onUidBiasChangedLocked(uid, prevBias, newBias);
}
+ mConcurrencyManager.onUidBiasChangedLocked(prevBias, newBias);
}
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 54e0a4c6663c..2a79ec4587fc 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -751,7 +751,8 @@ public final class JobServiceContext implements ServiceConnection {
}
}
mParams.setStopReason(stopReasonCode, internalStopReasonCode, debugReason);
- if (internalStopReasonCode == JobParameters.INTERNAL_STOP_REASON_PREEMPT) {
+ if (stopReasonCode == JobParameters.STOP_REASON_PREEMPT) {
+ // Only preserve the UID when we're preempting the job for another one of the same UID.
mPreferredUid = mRunningJob != null ? mRunningJob.getUid() : NO_PREFERRED_UID;
}
handleCancelLocked(debugReason);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index ee0f9e8f9658..fdcd2fc82ecc 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -297,9 +297,9 @@ public final class QuotaController extends StateController {
private final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
/**
- * List of jobs that started while the UID was in the TOP state. There will be no more than
- * 16 ({@link JobSchedulerService#MAX_JOB_CONTEXTS_COUNT}) running at once, so an ArraySet is
- * fine.
+ * List of jobs that started while the UID was in the TOP state. There will usually be no more
+ * than {@value JobConcurrencyManager#MAX_STANDARD_JOB_CONCURRENCY} running at once, so an
+ * ArraySet is fine.
*/
private final ArraySet<JobStatus> mTopStartedJobs = new ArraySet<>();
@@ -404,6 +404,10 @@ public final class QuotaController extends StateController {
@Override
public void onUidCachedChanged(int uid, boolean cached) {
}
+
+ @Override
+ public void onUidProcAdjChanged(int uid) {
+ }
}
/**
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
index fd6aa7a1d282..223091a27ee1 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
@@ -289,9 +289,9 @@ public class TareController extends StateController {
};
/**
- * List of jobs that started while the UID was in the TOP state. There will be no more than
- * 16 ({@link JobSchedulerService#MAX_JOB_CONTEXTS_COUNT}) running at once, so an ArraySet is
- * fine.
+ * List of jobs that started while the UID was in the TOP state. There will usually be no more
+ * than {@value JobConcurrencyManager#MAX_STANDARD_JOB_CONCURRENCY} running at once, so an
+ * ArraySet is fine.
*/
@GuardedBy("mLock")
private final ArraySet<JobStatus> mTopStartedJobs = new ArraySet<>();
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
index 5ec2f5607153..3578c8acbd0e 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
@@ -97,6 +97,10 @@ class ProcessStateModifier extends Modifier {
@Override
public void onUidCachedChanged(int uid, boolean cached) {
}
+
+ @Override
+ public void onUidProcAdjChanged(int uid) {
+ }
};
ProcessStateModifier(@NonNull InternalResourceService irs) {
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 b520102b2830..fde59ea1e5f3 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -1309,7 +1309,7 @@ public class AppStandbyController
return STANDBY_BUCKET_WORKING_SET;
}
- if (mInjector.hasScheduleExactAlarm(packageName, UserHandle.getUid(userId, appId))) {
+ if (mInjector.hasExactAlarmPermission(packageName, UserHandle.getUid(userId, appId))) {
return STANDBY_BUCKET_WORKING_SET;
}
}
@@ -2326,8 +2326,8 @@ public class AppStandbyController
return mWellbeingApp != null && mWellbeingApp.equals(packageName);
}
- boolean hasScheduleExactAlarm(String packageName, int uid) {
- return mAlarmManagerInternal.hasScheduleExactAlarm(packageName, uid);
+ boolean hasExactAlarmPermission(String packageName, int uid) {
+ return mAlarmManagerInternal.hasExactAlarmPermission(packageName, uid);
}
void updatePowerWhitelistCache() {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index f9317eba4e27..968be3e20791 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -1425,12 +1425,17 @@ void BootAnimation::drawTexturedQuad(float xStart, float yStart, float width, fl
void BootAnimation::initDynamicColors() {
for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) {
- parseColorDecimalString(
- android::base::GetProperty("persist.bootanim.color" + std::to_string(i + 1), ""),
+ const auto syspropName = "persist.bootanim.color" + std::to_string(i + 1);
+ const auto syspropValue = android::base::GetProperty(syspropName, "");
+ if (syspropValue != "") {
+ SLOGI("Loaded dynamic color: %s -> %s", syspropName.c_str(), syspropValue.c_str());
+ mDynamicColorsApplied = true;
+ }
+ parseColorDecimalString(syspropValue,
mAnimation->endColors[i], mAnimation->startColors[i]);
}
glUseProgram(mImageShader);
- SLOGI("[BootAnimation] Dynamically coloring boot animation.");
+ SLOGI("Dynamically coloring boot animation. Sysprops loaded? %i", mDynamicColorsApplied);
for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) {
float *startColor = mAnimation->startColors[i];
float *endColor = mAnimation->endColors[i];
@@ -1465,6 +1470,11 @@ bool BootAnimation::playAnimation(const Animation& animation) {
continue; //to next part
}
+ if (animation.dynamicColoringEnabled && part.useDynamicColoring && !mDynamicColorsApplied) {
+ SLOGD("Trying to load dynamic color sysprops.");
+ initDynamicColors();
+ }
+
// process the part not only while the count allows but also if already fading
for (int r=0 ; !part.count || r<part.count || fadedFramesCount > 0 ; r++) {
if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 4c378cbc48bd..a136ad0a90f2 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -228,6 +228,7 @@ private:
bool mTimeIsAccurate;
bool mTimeFormat12Hour;
bool mShuttingDown;
+ bool mDynamicColorsApplied = false;
String8 mZipFileName;
SortedVector<String8> mLoadedFiles;
sp<TimeCheckThread> mTimeCheckThread = nullptr;
diff --git a/core/api/current.txt b/core/api/current.txt
index c7b8d32f77a9..89b994189e92 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -110,7 +110,6 @@ package android {
field public static final String MANAGE_MEDIA = "android.permission.MANAGE_MEDIA";
field public static final String MANAGE_ONGOING_CALLS = "android.permission.MANAGE_ONGOING_CALLS";
field public static final String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
- field @Deprecated public static final String MANAGE_WIFI_AUTO_JOIN = "android.permission.MANAGE_WIFI_AUTO_JOIN";
field public static final String MANAGE_WIFI_INTERFACES = "android.permission.MANAGE_WIFI_INTERFACES";
field public static final String MANAGE_WIFI_NETWORK_SELECTION = "android.permission.MANAGE_WIFI_NETWORK_SELECTION";
field public static final String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
@@ -4158,7 +4157,7 @@ package android.app {
method protected void onActivityResult(int, int, android.content.Intent);
method @Deprecated public void onAttachFragment(android.app.Fragment);
method public void onAttachedToWindow();
- method public void onBackPressed();
+ method @Deprecated public void onBackPressed();
method protected void onChildTitleChanged(android.app.Activity, CharSequence);
method public void onConfigurationChanged(@NonNull android.content.res.Configuration);
method public void onContentChanged();
@@ -5050,7 +5049,7 @@ package android.app {
method @CallSuper public void onActionModeFinished(android.view.ActionMode);
method @CallSuper public void onActionModeStarted(android.view.ActionMode);
method public void onAttachedToWindow();
- method public void onBackPressed();
+ method @Deprecated public void onBackPressed();
method public void onContentChanged();
method public boolean onContextItemSelected(@NonNull android.view.MenuItem);
method public void onContextMenuClosed(@NonNull android.view.Menu);
@@ -9226,6 +9225,7 @@ package android.content {
field public static final int CLASSIFICATION_NOT_COMPLETE = 1; // 0x1
field public static final int CLASSIFICATION_NOT_PERFORMED = 2; // 0x2
field @NonNull public static final android.os.Parcelable.Creator<android.content.ClipDescription> CREATOR;
+ field public static final String EXTRA_IS_SENSITIVE = "android.content.extra.IS_SENSITIVE";
field public static final String MIMETYPE_TEXT_HTML = "text/html";
field public static final String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent";
field public static final String MIMETYPE_TEXT_PLAIN = "text/plain";
@@ -32947,6 +32947,7 @@ package android.preference {
method @Deprecated public boolean isMultiPane();
method @Deprecated protected boolean isValidFragment(String);
method @Deprecated public void loadHeadersFromResource(@XmlRes int, java.util.List<android.preference.PreferenceActivity.Header>);
+ method @Deprecated public void onBackPressed();
method @Deprecated public void onBuildHeaders(java.util.List<android.preference.PreferenceActivity.Header>);
method @Deprecated public android.content.Intent onBuildStartFragmentIntent(String, android.os.Bundle, @StringRes int, int);
method @Deprecated public android.preference.PreferenceActivity.Header onGetInitialHeader();
@@ -33406,6 +33407,7 @@ package android.print {
public final class PrintManager {
method @NonNull public java.util.List<android.print.PrintJob> getPrintJobs();
+ method public boolean isPrintServiceEnabled(@NonNull android.content.ComponentName);
method @NonNull public android.print.PrintJob print(@NonNull String, @NonNull android.print.PrintDocumentAdapter, @Nullable android.print.PrintAttributes);
}
@@ -37578,10 +37580,12 @@ package android.security {
public class KeyStoreException extends java.lang.Exception {
method public int getNumericErrorCode();
+ method public int getRetryPolicy();
method public boolean isSystemError();
method public boolean isTransientFailure();
method public boolean requiresUserAuthentication();
field public static final int ERROR_ATTESTATION_CHALLENGE_TOO_LARGE = 9; // 0x9
+ field public static final int ERROR_ATTESTATION_KEYS_UNAVAILABLE = 16; // 0x10
field public static final int ERROR_ID_ATTESTATION_FAILURE = 8; // 0x8
field public static final int ERROR_INCORRECT_USAGE = 13; // 0xd
field public static final int ERROR_INTERNAL_SYSTEM_ERROR = 4; // 0x4
@@ -37596,6 +37600,9 @@ package android.security {
field public static final int ERROR_PERMISSION_DENIED = 5; // 0x5
field public static final int ERROR_UNIMPLEMENTED = 12; // 0xc
field public static final int ERROR_USER_AUTHENTICATION_REQUIRED = 2; // 0x2
+ field public static final int RETRY_NEVER = 1; // 0x1
+ field public static final int RETRY_WHEN_CONNECTIVITY_AVAILABLE = 3; // 0x3
+ field public static final int RETRY_WITH_EXPONENTIAL_BACKOFF = 2; // 0x2
}
@Deprecated public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
@@ -39634,12 +39641,9 @@ package android.speech {
public final class RecognitionSupport implements android.os.Parcelable {
method public int describeContents();
- method @Deprecated @NonNull public java.util.List<java.lang.String> getInstalledLanguages();
method @NonNull public java.util.List<java.lang.String> getInstalledOnDeviceLanguages();
method @NonNull public java.util.List<java.lang.String> getOnlineLanguages();
- method @Deprecated @NonNull public java.util.List<java.lang.String> getPendingLanguages();
method @NonNull public java.util.List<java.lang.String> getPendingOnDeviceLanguages();
- method @Deprecated @NonNull public java.util.List<java.lang.String> getSupportedLanguages();
method @NonNull public java.util.List<java.lang.String> getSupportedOnDeviceLanguages();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.speech.RecognitionSupport> CREATOR;
@@ -39647,20 +39651,14 @@ package android.speech {
public static final class RecognitionSupport.Builder {
ctor public RecognitionSupport.Builder();
- method @Deprecated @NonNull public android.speech.RecognitionSupport.Builder addInstalledLanguage(@NonNull String);
method @NonNull public android.speech.RecognitionSupport.Builder addInstalledOnDeviceLanguage(@NonNull String);
method @NonNull public android.speech.RecognitionSupport.Builder addOnlineLanguage(@NonNull String);
- method @Deprecated @NonNull public android.speech.RecognitionSupport.Builder addPendingLanguage(@NonNull String);
method @NonNull public android.speech.RecognitionSupport.Builder addPendingOnDeviceLanguage(@NonNull String);
- method @Deprecated @NonNull public android.speech.RecognitionSupport.Builder addSupportedLanguage(@NonNull String);
method @NonNull public android.speech.RecognitionSupport.Builder addSupportedOnDeviceLanguage(@NonNull String);
method @NonNull public android.speech.RecognitionSupport build();
- method @Deprecated @NonNull public android.speech.RecognitionSupport.Builder setInstalledLanguages(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.speech.RecognitionSupport.Builder setInstalledOnDeviceLanguages(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.speech.RecognitionSupport.Builder setOnlineLanguages(@NonNull java.util.List<java.lang.String>);
- method @Deprecated @NonNull public android.speech.RecognitionSupport.Builder setPendingLanguages(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.speech.RecognitionSupport.Builder setPendingOnDeviceLanguages(@NonNull java.util.List<java.lang.String>);
- method @Deprecated @NonNull public android.speech.RecognitionSupport.Builder setSupportedLanguages(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.speech.RecognitionSupport.Builder setSupportedOnDeviceLanguages(@NonNull java.util.List<java.lang.String>);
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 30a43c06087c..3f8fc5600eb1 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -296,7 +296,6 @@ package android {
field public static final String SECURE_ELEMENT_PRIVILEGED_OPERATION = "android.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION";
field public static final String SEND_CATEGORY_CAR_NOTIFICATIONS = "android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS";
field public static final String SEND_DEVICE_CUSTOMIZATION_READY = "android.permission.SEND_DEVICE_CUSTOMIZATION_READY";
- field public static final String SEND_LOST_MODE_LOCATION_UPDATES = "android.permission.SEND_LOST_MODE_LOCATION_UPDATES";
field public static final String SEND_SAFETY_CENTER_UPDATE = "android.permission.SEND_SAFETY_CENTER_UPDATE";
field public static final String SEND_SHOW_SUSPENDED_APP_DETAILS = "android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS";
field public static final String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
@@ -2785,6 +2784,9 @@ package android.companion.virtual {
public final class VirtualDeviceManager {
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.VirtualDeviceManager.VirtualDevice createVirtualDevice(int, @NonNull android.companion.virtual.VirtualDeviceParams);
+ field public static final int LAUNCH_FAILURE_NO_ACTIVITY = 2; // 0x2
+ field public static final int LAUNCH_FAILURE_PENDING_INTENT_CANCELED = 1; // 0x1
+ field public static final int LAUNCH_SUCCESS = 0; // 0x0
}
public static interface VirtualDeviceManager.ActivityListener {
@@ -2792,11 +2794,6 @@ package android.companion.virtual {
method public void onTopActivityChanged(int, @NonNull android.content.ComponentName);
}
- public static interface VirtualDeviceManager.LaunchCallback {
- method public void onLaunchFailed();
- method public void onLaunchSuccess();
- }
-
public static class VirtualDeviceManager.VirtualDevice implements java.lang.AutoCloseable {
method public void addActivityListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
@@ -2805,7 +2802,7 @@ package android.companion.virtual {
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
- method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.LaunchCallback);
+ method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setShowPointerIcon(boolean);
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index f7bf716fe8e5..5bb6325d33db 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -36,6 +36,7 @@ package android {
field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
field public static final String RECORD_BACKGROUND_AUDIO = "android.permission.RECORD_BACKGROUND_AUDIO";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+ field public static final String REQUEST_UNIQUE_ID_ATTESTATION = "android.permission.REQUEST_UNIQUE_ID_ATTESTATION";
field public static final String RESET_APP_ERRORS = "android.permission.RESET_APP_ERRORS";
field public static final String REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL = "android.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL";
field public static final String SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS = "android.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS";
@@ -1190,6 +1191,9 @@ package android.hardware.display {
method public boolean alwaysOnAvailable();
method public boolean alwaysOnAvailableForUser(int);
method public boolean alwaysOnEnabled(int);
+ method public void disableDozeSettings(int);
+ method public void disableDozeSettings(boolean, int);
+ method public void restoreDozeSettings(int);
}
public final class DisplayManager {
@@ -3261,10 +3265,6 @@ package android.window {
field public static final int FEATURE_WINDOW_TOKENS = 2; // 0x2
}
- public interface OnBackInvokedDispatcher {
- field public static final long DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME = 195946584L; // 0xbade858L
- }
-
public final class SplashScreenView extends android.widget.FrameLayout {
method @Nullable public android.view.View getBrandingView();
}
diff --git a/core/java/android/accessibilityservice/MagnificationConfig.java b/core/java/android/accessibilityservice/MagnificationConfig.java
index 74c91d6097c3..ddafb224a5cd 100644
--- a/core/java/android/accessibilityservice/MagnificationConfig.java
+++ b/core/java/android/accessibilityservice/MagnificationConfig.java
@@ -42,9 +42,9 @@ import java.lang.annotation.RetentionPolicy;
* </p>
*
* <p>
- * When the magnification config uses {@link #MAGNIFICATION_MODE_WINDOW}.
- * {@link AccessibilityService} will be able to control the activated window magnifier
- * on the display.
+ * When the magnification config uses {@link #MAGNIFICATION_MODE_WINDOW} and the platform
+ * supports {@link android.content.pm.PackageManager#FEATURE_WINDOW_MAGNIFICATION} feature.
+ * {@link AccessibilityService} will be able to control window magnifier on the display.
* </p>
*
* <p>
@@ -57,9 +57,12 @@ public final class MagnificationConfig implements Parcelable {
/** The controlling magnification mode. It controls the activated magnifier. */
public static final int MAGNIFICATION_MODE_DEFAULT = 0;
- /** The controlling magnification mode. It controls fullscreen magnifier. */
+ /** The controlling magnification mode. It controls full-screen magnifier. */
public static final int MAGNIFICATION_MODE_FULLSCREEN = 1;
- /** The controlling magnification mode. It controls window magnifier. */
+ /**
+ * The controlling magnification mode. It is valid if the platform supports
+ * {@link android.content.pm.PackageManager#FEATURE_WINDOW_MAGNIFICATION} feature.
+ */
public static final int MAGNIFICATION_MODE_WINDOW = 2;
/** @hide */
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 5eda587cf7c8..dff3c076727d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3938,7 +3938,11 @@ public class Activity extends ContextThemeWrapper
* </ul>
*
* @see #moveTaskToBack(boolean)
+ *
+ * @deprecated Use {@link OnBackInvokedCallback} or
+ * {@code androidx.activity.OnBackPressedCallback} to handle back navigation instead.
*/
+ @Deprecated
public void onBackPressed() {
if (mActionBar != null && mActionBar.collapseActionView()) {
return;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 88844b516726..458dd5d804d1 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -222,6 +222,9 @@ public class ActivityManager {
@Override public void onUidCachedChanged(int uid, boolean cached) {
}
+
+ @Override public void onUidProcAdjChanged(int uid) {
+ }
}
final ArrayMap<OnUidImportanceListener, UidObserver> mImportanceListeners = new ArrayMap<>();
@@ -825,6 +828,9 @@ public class ActivityManager {
/** @hide Flag for registerUidObserver: report uid capability has changed. */
public static final int UID_OBSERVER_CAPABILITY = 1<<5;
+ /** @hide Flag for registerUidObserver: report pid oom adj has changed. */
+ public static final int UID_OBSERVER_PROC_OOM_ADJ = 1 << 6;
+
/** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: normal free-to-run operation. */
public static final int APP_START_MODE_NORMAL = 0;
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index a763b1464b6d..72c7fe4c5b40 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -726,7 +726,11 @@ public class Dialog implements DialogInterface, Window.Callback,
* Called when the dialog has detected the user's press of the back
* key. The default implementation simply cancels the dialog (only if
* it is cancelable), but you can override this to do whatever you want.
+ *
+ * @deprecated Use {@link OnBackInvokedCallback} or
+ * {@code androidx.activity.OnBackPressedCallback} to handle back navigation instead.
*/
+ @Deprecated
public void onBackPressed() {
if (mCancelable) {
cancel();
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 87b2417af53f..201473f4957e 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -268,6 +268,12 @@ interface IActivityTaskManager {
android.window.TaskSnapshot getTaskSnapshot(int taskId, boolean isLowResolution);
/**
+ * @param taskId the id of the task to take a snapshot of
+ * @return a graphic buffer representing a screenshot of a task
+ */
+ android.window.TaskSnapshot takeTaskSnapshot(int taskId);
+
+ /**
* Return the user id of last resumed activity.
*/
int getLastResumedActivityUserId();
diff --git a/core/java/android/app/IUidObserver.aidl b/core/java/android/app/IUidObserver.aidl
index 74018a8ab1f8..0c920f1359f3 100644
--- a/core/java/android/app/IUidObserver.aidl
+++ b/core/java/android/app/IUidObserver.aidl
@@ -54,6 +54,13 @@ oneway interface IUidObserver {
*/
void onUidStateChanged(int uid, int procState, long procStateSeq, int capability);
+ /**
+ * Report a proc oom adj change associated with a uid.
+ *
+ * @param uid The uid for which the state change is being reported.
+ */
+ void onUidProcAdjChanged(int uid);
+
// =============== End of transactions used on native side as well ============================
/**
diff --git a/core/java/android/app/LocaleManager.java b/core/java/android/app/LocaleManager.java
index efe9e35d4c64..794c6946f7a8 100644
--- a/core/java/android/app/LocaleManager.java
+++ b/core/java/android/app/LocaleManager.java
@@ -54,8 +54,18 @@ public class LocaleManager {
*
* <p>Pass a {@link LocaleList#getEmptyLocaleList()} to reset to the system locale.
*
- * <p><b>Note:</b> The set locales are persisted; they are backed up if the user has enabled
- * Backup & Restore.
+ * <p><b>Note:</b> Changes to app locales will result in a configuration change (and potentially
+ * an Activity lifecycle event) being applied to the calling application. For more information,
+ * see the <a
+ * href="https://developer.android.com/guide/topics/resources/runtime-changes">section on
+ * handling configuration changes</a>. The set locales are persisted; they are backed up if the
+ * user has enabled Backup & Restore.
+ *
+ * <p><b>Note:</b> Users' locale preferences are passed to applications by creating a union of
+ * any app-specific locales and system locales, with the app-specific locales appearing first.
+ * Language resources are then chosen per usual (as described in the <a
+ * href="https://developer.android.com/guide/topics/resources/multilingual-support">section on
+ * locale resolution</a>).
*
* @param locales the desired locales for the calling app.
*/
@@ -69,8 +79,18 @@ public class LocaleManager {
*
* <p>Pass a {@link LocaleList#getEmptyLocaleList()} to reset to the system locale.
*
- * <p><b>Note:</b> The set locales are persisted; they are backed up if the user has enabled
- * Backup & Restore.
+ * <p><b>Note:</b> Changes to app locales will result in a configuration change (and potentially
+ * an Activity lifecycle event) being applied to the specified application. For more
+ * information, see the <a
+ * href="https://developer.android.com/guide/topics/resources/runtime-changes">section on
+ * handling configuration changes</a>. The set locales are persisted; they are backed up if the
+ * user has enabled Backup & Restore.
+ *
+ * <p><b>Note:</b> Users' locale preferences are passed to applications by creating a union of
+ * any app-specific locales and system locales, with the app-specific locales appearing first.
+ * Language resources are then chosen per usual (as described in the <a
+ * href="https://developer.android.com/guide/topics/resources/multilingual-support">section on
+ * locale resolution</a>).
*
* @param appPackageName the package name of the app for which to set the locales.
* @param locales the desired locales for the specified app.
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 1a38fcfba5a0..1b87945ec985 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -472,7 +472,8 @@ public class TaskInfo {
&& isFocused == that.isFocused
&& isVisible == that.isVisible
&& isSleeping == that.isSleeping
- && Objects.equals(mTopActivityLocusId, that.mTopActivityLocusId);
+ && Objects.equals(mTopActivityLocusId, that.mTopActivityLocusId)
+ && parentTaskId == that.parentTaskId;
}
/**
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 5e521b03f6e3..893dc2f6ace4 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -1209,7 +1209,9 @@ public final class UiAutomation {
* @see android.view.WindowAnimationFrameStats
* @see #getWindowAnimationFrameStats()
* @see android.R.styleable#WindowAnimation
- * @deprecated animation-frames are no-longer used.
+ * @deprecated animation-frames are no-longer used. Use Shared
+ * <a href="https://perfetto.dev/docs/data-sources/frametimeline">FrameTimeline</a>
+ * jank metrics instead.
*/
@Deprecated
public void clearWindowAnimationFrameStats() {
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 5c1ab3879487..e502ba03bf8e 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -222,9 +222,6 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
})
public @interface WindowConfig {}
- /** @hide */
- public static final int PINNED_WINDOWING_MODE_ELEVATION_IN_DIP = 5;
-
@UnsupportedAppUsage
public WindowConfiguration() {
unset();
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index f9f0c58b2200..88ffdecfb537 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -64,6 +64,7 @@ import android.nfc.NfcAdapter;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.IpcDataCache;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.PersistableBundle;
@@ -3781,6 +3782,60 @@ public class DevicePolicyManager {
public static final String EXTRA_RESOURCE_IDS =
"android.app.extra.RESOURCE_IDS";
+ /**
+ * A convenience class that wraps some IpcDataCache methods. Instantiate it with an
+ * API string. Instances can and should be final static. All instances of this class
+ * use the same key for invalidation.
+ */
+ private static class BinderApi {
+ private final static String KEY = "DevicePolicyManager";
+ private final String mApi;
+ BinderApi(String api) {
+ mApi = api;
+ }
+ final String api() {
+ return mApi;
+ }
+ final String key() {
+ return KEY;
+ }
+ final static void invalidate() {
+ IpcDataCache.invalidateCache(IpcDataCache.MODULE_SYSTEM, KEY);
+ }
+ final void disable() {
+ IpcDataCache.disableForCurrentProcess(mApi);
+ }
+ }
+
+ /** @hide */
+ public static void invalidateBinderCaches() {
+ BinderApi.invalidate();
+ }
+
+ /**
+ * A simple wrapper for binder caches in this class. All caches are created with a
+ * maximum of 8 entries, the SYSTEM module, and a cache name that is the same as the api.
+ */
+ private static class BinderCache<Q,R> extends IpcDataCache<Q,R> {
+ BinderCache(BinderApi api, IpcDataCache.QueryHandler<Q,R> handler) {
+ super(8, IpcDataCache.MODULE_SYSTEM, api.key(), api.api(), handler);
+ }
+ }
+
+ /**
+ * Disable all caches in the local process.
+ * @hide
+ */
+ public static void disableLocalProcessCaches() {
+ disableGetKeyguardDisabledFeaturesCache();
+ disableHasDeviceOwnerCache();
+ disableGetProfileOwnerOrDeviceOwnerSupervisionComponentCache();
+ disableIsOrganizationOwnedDeviceWithManagedProfileCache();
+ disableGetDeviceOwnerOrganizationNameCache();
+ disableGetOrganizationNameForUserCache();
+ disableIsNetworkLoggingEnabled();
+ }
+
/** @hide */
@NonNull
@TestApi
@@ -8380,17 +8435,57 @@ public class DevicePolicyManager {
return getKeyguardDisabledFeatures(admin, myUserId());
}
+ // A key into the keyguard cache.
+ private static class KeyguardQuery {
+ private final ComponentName mAdmin;
+ private final int mUserHandle;
+ KeyguardQuery(@Nullable ComponentName admin, int userHandle) {
+ mAdmin = admin;
+ mUserHandle = userHandle;
+ }
+ public boolean equals(Object o) {
+ if (o instanceof KeyguardQuery) {
+ KeyguardQuery r = (KeyguardQuery) o;
+ return Objects.equals(mAdmin, r.mAdmin) && mUserHandle == r.mUserHandle;
+ } else {
+ return false;
+ }
+ }
+ public int hashCode() {
+ return ((mAdmin != null) ? mAdmin.hashCode() : 0) * 13 + mUserHandle;
+ }
+ }
+
+ // The query handler does not cache wildcard user IDs, although they should never
+ // appear in the query.
+ private static final BinderApi sGetKeyguardDisabledFeatures =
+ new BinderApi("getKeyguardDisabledFeatures");
+ private BinderCache<KeyguardQuery, Integer> mGetKeyGuardDisabledFeaturesCache =
+ new BinderCache<>(sGetKeyguardDisabledFeatures,
+ new IpcDataCache.QueryHandler<KeyguardQuery, Integer>() {
+ @Override
+ public Integer apply(KeyguardQuery query) {
+ try {
+ return mService.getKeyguardDisabledFeatures(
+ query.mAdmin, query.mUserHandle, mParentInstance);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }});
+
+ /** @hide */
+ public static void disableGetKeyguardDisabledFeaturesCache() {
+ sGetKeyguardDisabledFeatures.disable();
+ }
+
/** @hide per-user version */
@UnsupportedAppUsage
public int getKeyguardDisabledFeatures(@Nullable ComponentName admin, int userHandle) {
if (mService != null) {
- try {
- return mService.getKeyguardDisabledFeatures(admin, userHandle, mParentInstance);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return mGetKeyGuardDisabledFeaturesCache.query(new KeyguardQuery(admin, userHandle));
+ } else {
+ return KEYGUARD_DISABLE_FEATURES_NONE;
}
- return KEYGUARD_DISABLE_FEATURES_NONE;
}
/**
@@ -8769,6 +8864,24 @@ public class DevicePolicyManager {
return name != null ? name.getPackageName() : null;
}
+ private static final BinderApi sHasDeviceOwner =
+ new BinderApi("hasDeviceOwner");
+ private BinderCache<Void, Boolean> mHasDeviceOwnerCache =
+ new BinderCache<>(sHasDeviceOwner,
+ new IpcDataCache.QueryHandler<Void, Boolean>() {
+ @Override
+ public Boolean apply(Void query) {
+ try {
+ return mService.hasDeviceOwner();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }});
+ /** @hide */
+ public static void disableHasDeviceOwnerCache() {
+ sHasDeviceOwner.disable();
+ }
+
/**
* Called by the system to find out whether the device is managed by a Device Owner.
*
@@ -8781,11 +8894,7 @@ public class DevicePolicyManager {
@SystemApi
@SuppressLint("RequiresPermission")
public boolean isDeviceManaged() {
- try {
- return mService.hasDeviceOwner();
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
+ return mHasDeviceOwnerCache.query(null);
}
/**
@@ -9147,6 +9256,26 @@ public class DevicePolicyManager {
return null;
}
+ private final static BinderApi sGetProfileOwnerOrDeviceOwnerSupervisionComponent =
+ new BinderApi("getProfileOwnerOrDeviceOwnerSupervisionComponent");
+ private final BinderCache<UserHandle, ComponentName>
+ mGetProfileOwnerOrDeviceOwnerSupervisionComponentCache =
+ new BinderCache(sGetProfileOwnerOrDeviceOwnerSupervisionComponent,
+ new IpcDataCache.QueryHandler<UserHandle, ComponentName>() {
+ @Override
+ public ComponentName apply(UserHandle user) {
+ try {
+ return mService.getProfileOwnerOrDeviceOwnerSupervisionComponent(
+ user);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }});
+ /** @hide */
+ public static void disableGetProfileOwnerOrDeviceOwnerSupervisionComponentCache() {
+ sGetProfileOwnerOrDeviceOwnerSupervisionComponent.disable();
+ }
+
/**
* Returns the configured supervision app if it exists and is the device owner or policy owner.
* @hide
@@ -9154,11 +9283,7 @@ public class DevicePolicyManager {
public @Nullable ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent(
@NonNull UserHandle user) {
if (mService != null) {
- try {
- return mService.getProfileOwnerOrDeviceOwnerSupervisionComponent(user);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
+ return mGetProfileOwnerOrDeviceOwnerSupervisionComponentCache.query(user);
}
return null;
}
@@ -9204,6 +9329,24 @@ public class DevicePolicyManager {
return null;
}
+ private final static BinderApi sIsOrganizationOwnedDeviceWithManagedProfile =
+ new BinderApi("isOrganizationOwnedDeviceWithManagedProfile");
+ private final BinderCache<Void, Boolean> mIsOrganizationOwnedDeviceWithManagedProfileCache =
+ new BinderCache(sIsOrganizationOwnedDeviceWithManagedProfile,
+ new IpcDataCache.QueryHandler<Void, Boolean>() {
+ @Override
+ public Boolean apply(Void query) {
+ try {
+ return mService.isOrganizationOwnedDeviceWithManagedProfile();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }});
+ /** @hide */
+ public static void disableIsOrganizationOwnedDeviceWithManagedProfileCache() {
+ sIsOrganizationOwnedDeviceWithManagedProfile.disable();
+ }
+
/**
* Apps can use this method to find out if the device was provisioned as
* organization-owend device with a managed profile.
@@ -9220,11 +9363,7 @@ public class DevicePolicyManager {
public boolean isOrganizationOwnedDeviceWithManagedProfile() {
throwIfParentInstance("isOrganizationOwnedDeviceWithManagedProfile");
if (mService != null) {
- try {
- return mService.isOrganizationOwnedDeviceWithManagedProfile();
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
+ return mIsOrganizationOwnedDeviceWithManagedProfileCache.query(null);
}
return false;
}
@@ -12788,6 +12927,24 @@ public class DevicePolicyManager {
}
}
+ private final static BinderApi sGetDeviceOwnerOrganizationName =
+ new BinderApi("getDeviceOwnerOrganizationName");
+ private final BinderCache<Void, CharSequence> mGetDeviceOwnerOrganizationNameCache =
+ new BinderCache(sGetDeviceOwnerOrganizationName,
+ new IpcDataCache.QueryHandler<Void, CharSequence>() {
+ @Override
+ public CharSequence apply(Void query) {
+ try {
+ return mService.getDeviceOwnerOrganizationName();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }});
+ /** @hide */
+ public static void disableGetDeviceOwnerOrganizationNameCache() {
+ sGetDeviceOwnerOrganizationName.disable();
+ }
+
/**
* Called by the system to retrieve the name of the organization managing the device.
*
@@ -12800,11 +12957,25 @@ public class DevicePolicyManager {
@SystemApi
@SuppressLint("RequiresPermission")
public @Nullable CharSequence getDeviceOwnerOrganizationName() {
- try {
- return mService.getDeviceOwnerOrganizationName();
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
+ return mGetDeviceOwnerOrganizationNameCache.query(null);
+ }
+
+ private final static BinderApi sGetOrganizationNameForUser =
+ new BinderApi("getOrganizationNameForUser");
+ private final BinderCache<Integer, CharSequence> mGetOrganizationNameForUserCache =
+ new BinderCache(sGetOrganizationNameForUser,
+ new IpcDataCache.QueryHandler<Integer, CharSequence>() {
+ @Override
+ public CharSequence apply(Integer userHandle) {
+ try {
+ return mService.getOrganizationNameForUser(userHandle);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }});
+ /** @hide */
+ public static void disableGetOrganizationNameForUserCache() {
+ sGetOrganizationNameForUser.disable();
}
/**
@@ -12816,11 +12987,7 @@ public class DevicePolicyManager {
* @hide
*/
public @Nullable CharSequence getOrganizationNameForUser(int userHandle) {
- try {
- return mService.getOrganizationNameForUser(userHandle);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
+ return mGetOrganizationNameForUserCache.query(userHandle);
}
/**
@@ -13205,6 +13372,25 @@ public class DevicePolicyManager {
}
}
+ private final static BinderApi sNetworkLoggingApi = new BinderApi("isNetworkLoggingEnabled");
+ private BinderCache<ComponentName, Boolean> mIsNetworkLoggingEnabledCache =
+ new BinderCache<>(sNetworkLoggingApi,
+ new IpcDataCache.QueryHandler<ComponentName, Boolean>() {
+ @Override
+ public Boolean apply(ComponentName admin) {
+ try {
+ return mService.isNetworkLoggingEnabled(
+ admin, mContext.getPackageName());
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }});
+
+ /** @hide */
+ public static void disableIsNetworkLoggingEnabled() {
+ sNetworkLoggingApi.disable();
+ }
+
/**
* Return whether network logging is enabled by a device owner or profile owner of
* a managed profile.
@@ -13219,11 +13405,7 @@ public class DevicePolicyManager {
*/
public boolean isNetworkLoggingEnabled(@Nullable ComponentName admin) {
throwIfParentInstance("isNetworkLoggingEnabled");
- try {
- return mService.isNetworkLoggingEnabled(admin, mContext.getPackageName());
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
+ return mIsNetworkLoggingEnabledCache.query(admin);
}
/**
diff --git a/core/java/android/app/ambientcontext/IAmbientContextManager.aidl b/core/java/android/app/ambientcontext/IAmbientContextManager.aidl
index 3b15bcb9846d..0d9ecfdfe8f6 100644
--- a/core/java/android/app/ambientcontext/IAmbientContextManager.aidl
+++ b/core/java/android/app/ambientcontext/IAmbientContextManager.aidl
@@ -25,7 +25,7 @@ import android.os.RemoteCallback;
*
* @hide
*/
-oneway interface IAmbientContextManager {
+interface IAmbientContextManager {
void registerObserver(in AmbientContextEventRequest request,
in PendingIntent resultPendingIntent,
in RemoteCallback statusCallback);
@@ -33,4 +33,4 @@ oneway interface IAmbientContextManager {
void queryServiceStatus(in int[] eventTypes, in String callingPackage,
in RemoteCallback statusCallback);
void startConsentActivity(in int[] eventTypes, in String callingPackage);
-} \ No newline at end of file
+}
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl
index e2859998efd4..8cfbf2faee67 100644
--- a/core/java/android/companion/virtual/IVirtualDevice.aidl
+++ b/core/java/android/companion/virtual/IVirtualDevice.aidl
@@ -17,7 +17,8 @@
package android.companion.virtual;
import android.app.PendingIntent;
-import android.companion.virtual.audio.IAudioSessionCallback;
+import android.companion.virtual.audio.IAudioConfigChangedCallback;
+import android.companion.virtual.audio.IAudioRoutingCallback;
import android.graphics.Point;
import android.graphics.PointF;
import android.hardware.input.VirtualKeyEvent;
@@ -51,7 +52,8 @@ interface IVirtualDevice {
*/
void onAudioSessionStarting(
int displayId,
- IAudioSessionCallback callback);
+ IAudioRoutingCallback routingCallback,
+ IAudioConfigChangedCallback configChangedCallback);
void onAudioSessionEnded();
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 914b321b7506..3bb837317ad4 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -17,13 +17,13 @@
package android.companion.virtual;
import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
-import android.app.Activity;
import android.app.PendingIntent;
import android.companion.AssociationInfo;
import android.companion.virtual.audio.VirtualAudioDevice;
@@ -48,7 +48,12 @@ import android.os.ResultReceiver;
import android.util.ArrayMap;
import android.view.Surface;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.util.concurrent.Executor;
+import java.util.function.IntConsumer;
/**
* System level service for managing virtual devices.
@@ -70,6 +75,35 @@ public final class VirtualDeviceManager {
| DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH
| DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = "LAUNCH_",
+ value = {
+ LAUNCH_SUCCESS,
+ LAUNCH_FAILURE_PENDING_INTENT_CANCELED,
+ LAUNCH_FAILURE_NO_ACTIVITY})
+ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+ public @interface PendingIntentLaunchStatus {}
+
+ /**
+ * Status for {@link VirtualDevice#launchPendingIntent}, indicating that the launch was
+ * successful.
+ */
+ public static final int LAUNCH_SUCCESS = 0;
+
+ /**
+ * Status for {@link VirtualDevice#launchPendingIntent}, indicating that the launch failed
+ * because the pending intent was canceled.
+ */
+ public static final int LAUNCH_FAILURE_PENDING_INTENT_CANCELED = 1;
+
+ /**
+ * Status for {@link VirtualDevice#launchPendingIntent}, indicating that the launch failed
+ * because no activity starts were detected as a result of calling the pending intent.
+ */
+ public static final int LAUNCH_FAILURE_NO_ACTIVITY = 2;
+
private final IVirtualDeviceManager mService;
private final Context mContext;
@@ -173,16 +207,20 @@ public final class VirtualDeviceManager {
* intent, the activity will be started on the virtual display using
* {@link android.app.ActivityOptions#setLaunchDisplayId}. If the intent is a service or
* broadcast intent, an attempt will be made to catch activities started as a result of
- * sending the pending intent and move them to the given display.
+ * sending the pending intent and move them to the given display. When it completes,
+ * {@code listener} will be called with the status of whether the launch attempt is
+ * successful or not.
* @param executor The executor to run {@code launchCallback} on.
- * @param launchCallback Callback that is called when the pending intent launching is
- * complete.
+ * @param listener Listener that is called when the pending intent launching is complete.
+ * The argument is {@link #LAUNCH_SUCCESS} if the launch successfully started an activity
+ * on the virtual display, or one of the {@code LAUNCH_FAILED} status explaining why it
+ * failed.
*/
public void launchPendingIntent(
int displayId,
@NonNull PendingIntent pendingIntent,
@NonNull Executor executor,
- @NonNull LaunchCallback launchCallback) {
+ @NonNull IntConsumer listener) {
try {
mVirtualDevice.launchPendingIntent(
displayId,
@@ -191,13 +229,7 @@ public final class VirtualDeviceManager {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
- executor.execute(() -> {
- if (resultCode == Activity.RESULT_OK) {
- launchCallback.onLaunchSuccess();
- } else {
- launchCallback.onLaunchFailed();
- }
- });
+ executor.execute(() -> listener.accept(resultCode));
}
});
} catch (RemoteException e) {
@@ -439,7 +471,7 @@ public final class VirtualDeviceManager {
* {@link #addActivityListener}.
*
* @param listener The listener to remove.
- * @see #addActivityListener(ActivityListener, Executor)
+ * @see #addActivityListener(Executor, ActivityListener)
*/
public void removeActivityListener(@NonNull ActivityListener listener) {
mActivityListeners.remove(listener);
@@ -447,21 +479,6 @@ public final class VirtualDeviceManager {
}
/**
- * Callback for launching pending intents on the virtual device.
- */
- public interface LaunchCallback {
- /**
- * Called when the pending intent launched successfully.
- */
- void onLaunchSuccess();
-
- /**
- * Called when the pending intent failed to launch.
- */
- void onLaunchFailed();
- }
-
- /**
* Listener for activity changes in this virtual device.
*/
public interface ActivityListener {
diff --git a/core/java/android/companion/virtual/audio/IAudioSessionCallback.aidl b/core/java/android/companion/virtual/audio/IAudioConfigChangedCallback.aidl
index e22ce148a9be..47b5e940b27a 100644
--- a/core/java/android/companion/virtual/audio/IAudioSessionCallback.aidl
+++ b/core/java/android/companion/virtual/audio/IAudioConfigChangedCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -20,15 +20,11 @@ import android.media.AudioPlaybackConfiguration;
import android.media.AudioRecordingConfiguration;
/**
- * Callback to control audio rerouting, notify playback and recording state of applications running
- * on virtual device.
+ * Callback to notify playback and recording state of applications running on virtual device.
*
* @hide
*/
-oneway interface IAudioSessionCallback {
-
- /** Updates the set of applications that need to have their audio rerouted. */
- void onAppsNeedingAudioRoutingChanged(in int[] appUids);
+oneway interface IAudioConfigChangedCallback {
/**
* Called whenever the playback configuration of applications running on virtual device has
diff --git a/core/java/android/companion/virtual/audio/IAudioRoutingCallback.aidl b/core/java/android/companion/virtual/audio/IAudioRoutingCallback.aidl
new file mode 100644
index 000000000000..a424d62266c9
--- /dev/null
+++ b/core/java/android/companion/virtual/audio/IAudioRoutingCallback.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 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.companion.virtual.audio;
+
+/**
+ * Callback to control audio rerouting for applications running on virtual device.
+ *
+ * @hide
+ */
+oneway interface IAudioRoutingCallback {
+
+ /** Updates the set of applications that need to have their audio rerouted. */
+ void onAppsNeedingAudioRoutingChanged(in int[] appUids);
+}
diff --git a/core/java/android/companion/virtual/audio/VirtualAudioDevice.java b/core/java/android/companion/virtual/audio/VirtualAudioDevice.java
index 3f7299fbb09e..0db7b5fe8289 100644
--- a/core/java/android/companion/virtual/audio/VirtualAudioDevice.java
+++ b/core/java/android/companion/virtual/audio/VirtualAudioDevice.java
@@ -76,8 +76,8 @@ public final class VirtualAudioDevice implements Closeable {
* @hide
*/
public VirtualAudioDevice(Context context, IVirtualDevice virtualDevice,
- VirtualDisplay virtualDisplay, Executor executor,
- AudioConfigurationChangeCallback callback) {
+ @NonNull VirtualDisplay virtualDisplay, @Nullable Executor executor,
+ @Nullable AudioConfigurationChangeCallback callback) {
mContext = context;
mVirtualDevice = virtualDevice;
mVirtualDisplay = virtualDisplay;
@@ -105,7 +105,8 @@ public final class VirtualAudioDevice implements Closeable {
try {
mVirtualDevice.onAudioSessionStarting(mVirtualDisplay.getDisplay().getDisplayId(),
- /* callback= */ mOngoingSession);
+ /* routingCallback= */ mOngoingSession,
+ /* configChangedCallback= */ mOngoingSession.getAudioConfigChangedListener());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -135,7 +136,8 @@ public final class VirtualAudioDevice implements Closeable {
try {
mVirtualDevice.onAudioSessionStarting(mVirtualDisplay.getDisplay().getDisplayId(),
- /* callback= */ mOngoingSession);
+ /* routingCallback= */ mOngoingSession,
+ /* configChangedCallback= */ mOngoingSession.getAudioConfigChangedListener());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/companion/virtual/audio/VirtualAudioSession.java b/core/java/android/companion/virtual/audio/VirtualAudioSession.java
index 524f6e2ab063..321a1c57643b 100644
--- a/core/java/android/companion/virtual/audio/VirtualAudioSession.java
+++ b/core/java/android/companion/virtual/audio/VirtualAudioSession.java
@@ -50,16 +50,14 @@ import java.util.concurrent.Executor;
* @hide
*/
@VisibleForTesting
-public final class VirtualAudioSession extends IAudioSessionCallback.Stub implements
+public final class VirtualAudioSession extends IAudioRoutingCallback.Stub implements
UserRestrictionsCallback, Closeable {
private static final String TAG = "VirtualAudioSession";
private final Context mContext;
private final UserRestrictionsDetector mUserRestrictionsDetector;
- /** The {@link Executor} for sending {@link AudioConfigurationChangeCallback} to the caller */
- private final Executor mExecutor;
@Nullable
- private final AudioConfigurationChangeCallback mCallback;
+ private final AudioConfigChangedCallback mAudioConfigChangedCallback;
private final Object mLock = new Object();
@GuardedBy("mLock")
private final IntArray mReroutedAppUids = new IntArray();
@@ -73,13 +71,44 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem
@GuardedBy("mLock")
private AudioInjection mAudioInjection;
+ /**
+ * Class to receive {@link IAudioConfigChangedCallback} callbacks from service.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public static final class AudioConfigChangedCallback extends IAudioConfigChangedCallback.Stub {
+ private final Executor mExecutor;
+ private final AudioConfigurationChangeCallback mCallback;
+
+ AudioConfigChangedCallback(Context context, Executor executor,
+ AudioConfigurationChangeCallback callback) {
+ mExecutor = executor != null ? executor : context.getMainExecutor();
+ mCallback = callback;
+ }
+
+ @Override
+ public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
+ if (mCallback != null) {
+ mExecutor.execute(() -> mCallback.onPlaybackConfigChanged(configs));
+ }
+ }
+
+ @Override
+ public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {
+ if (mCallback != null) {
+ mExecutor.execute(() -> mCallback.onRecordingConfigChanged(configs));
+ }
+ }
+ }
+
@VisibleForTesting
public VirtualAudioSession(Context context,
@Nullable AudioConfigurationChangeCallback callback, @Nullable Executor executor) {
mContext = context;
mUserRestrictionsDetector = new UserRestrictionsDetector(context);
- mCallback = callback;
- mExecutor = executor != null ? executor : context.getMainExecutor();
+ mAudioConfigChangedCallback = callback == null ? null : new AudioConfigChangedCallback(
+ context, executor, callback);
}
/**
@@ -132,6 +161,13 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem
/** @hide */
@VisibleForTesting
@Nullable
+ public AudioConfigChangedCallback getAudioConfigChangedListener() {
+ return mAudioConfigChangedCallback;
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ @Nullable
public AudioCapture getAudioCapture() {
synchronized (mLock) {
return mAudioCapture;
@@ -263,20 +299,6 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem
}
}
- @Override
- public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
- if (mCallback != null) {
- mExecutor.execute(() -> mCallback.onPlaybackConfigChanged(configs));
- }
- }
-
- @Override
- public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {
- if (mCallback != null) {
- mExecutor.execute(() -> mCallback.onRecordingConfigChanged(configs));
- }
- }
-
/** @hide */
@VisibleForTesting
public IntArray getReroutedAppUids() {
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index a086a308d0d9..c4ac483fd10e 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -21,6 +21,7 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa
import android.accounts.Account;
import android.annotation.MainThread;
import android.annotation.NonNull;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -171,8 +172,17 @@ public abstract class AbstractThreadedSyncAdapter {
}
private class ISyncAdapterImpl extends ISyncAdapter.Stub {
+ private void enforceCallerSystem() {
+ final long callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID) {
+ android.util.EventLog.writeEvent(0x534e4554, "203229608", -1, "");
+ return;
+ }
+ }
+
@Override
public void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb) {
+ enforceCallerSystem();
Handler.getMain().sendMessage(obtainMessage(
AbstractThreadedSyncAdapter::handleOnUnsyncableAccount,
AbstractThreadedSyncAdapter.this, cb));
@@ -187,6 +197,8 @@ public abstract class AbstractThreadedSyncAdapter {
}
Log.d(TAG, "startSync() start " + authority + " " + account + " " + extras);
}
+ enforceCallerSystem();
+
try {
final SyncContext syncContextClient = new SyncContext(syncContext);
@@ -242,6 +254,7 @@ public abstract class AbstractThreadedSyncAdapter {
@Override
public void cancelSync(ISyncContext syncContext) {
+ enforceCallerSystem();
try {
// synchronize to make sure that mSyncThreads doesn't change between when we
// check it and when we use it
diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java
index 2ecd71bc1f06..bf466116009b 100644
--- a/core/java/android/content/ClipDescription.java
+++ b/core/java/android/content/ClipDescription.java
@@ -134,6 +134,26 @@ public class ClipDescription implements Parcelable {
public static final String EXTRA_LOGGING_INSTANCE_ID =
"android.intent.extra.LOGGING_INSTANCE_ID";
+ /**
+ * Indicates that a ClipData contains potentially sensitive information, such as a
+ * password or credit card number.
+ * <p>
+ * Type: boolean
+ * </p>
+ * <p>
+ * This extra can be used to indicate that a ClipData contains sensitive information that
+ * should be redacted or hidden from view until a user takes explicit action to reveal it
+ * (e.g., by pasting).
+ * </p>
+ * <p>
+ * Adding this extra does not change clipboard behavior or add additional security to
+ * the ClipData. Its purpose is essentially a rendering hint from the source application,
+ * asking that the data within be obfuscated or redacted, unless the user has taken action
+ * to make it visible.
+ * </p>
+ */
+ public static final String EXTRA_IS_SENSITIVE = "android.content.extra.IS_SENSITIVE";
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(value =
diff --git a/core/java/android/content/pm/OWNERS b/core/java/android/content/pm/OWNERS
index 4e674f6ec9a8..087e61d70576 100644
--- a/core/java/android/content/pm/OWNERS
+++ b/core/java/android/content/pm/OWNERS
@@ -6,6 +6,7 @@ patb@google.com
per-file PackageParser.java = set noparent
per-file PackageParser.java = chiuwinson@google.com,patb@google.com,toddke@google.com
+per-file *Capability* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
per-file AppSearchPerson.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 227ac1a02890..a90f6d625c51 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4188,6 +4188,8 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
* supports window magnification.
+ *
+ * @see android.accessibilityservice.MagnificationConfig#MAGNIFICATION_MODE_WINDOW
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_WINDOW_MAGNIFICATION =
diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
index 0b1ed65ef937..7d8f2ff92200 100644
--- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java
+++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
@@ -22,14 +22,18 @@ import android.os.Build;
import android.os.SystemProperties;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.SparseArray;
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
+import java.util.Map;
+
/**
* AmbientDisplayConfiguration encapsulates reading access to the configuration of ambient display.
*
- * {@hide}
+ * @hide
*/
@TestApi
public class AmbientDisplayConfiguration {
@@ -37,14 +41,33 @@ public class AmbientDisplayConfiguration {
private final Context mContext;
private final boolean mAlwaysOnByDefault;
- /** {@hide} */
+ /** Copied from android.provider.Settings.Secure since these keys are hidden. */
+ private static final String[] DOZE_SETTINGS = {
+ Settings.Secure.DOZE_ENABLED,
+ Settings.Secure.DOZE_ALWAYS_ON,
+ Settings.Secure.DOZE_PICK_UP_GESTURE,
+ Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
+ Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
+ Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
+ Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE,
+ Settings.Secure.DOZE_TAP_SCREEN_GESTURE
+ };
+
+ /** Non-user configurable doze settings */
+ private static final String[] NON_USER_CONFIGURABLE_DOZE_SETTINGS = {
+ Settings.Secure.DOZE_QUICK_PICKUP_GESTURE
+ };
+
+ final SparseArray<Map<String, String>> mUsersInitialValues = new SparseArray<>();
+
+ /** @hide */
@TestApi
public AmbientDisplayConfiguration(Context context) {
mContext = context;
mAlwaysOnByDefault = mContext.getResources().getBoolean(R.bool.config_dozeAlwaysOnEnabled);
}
- /** {@hide} */
+ /** @hide */
public boolean enabled(int user) {
return pulseOnNotificationEnabled(user)
|| pulseOnLongPressEnabled(user)
@@ -58,35 +81,35 @@ public class AmbientDisplayConfiguration {
|| screenOffUdfpsEnabled(user);
}
- /** {@hide} */
+ /** @hide */
public boolean pulseOnNotificationEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_ENABLED, user)
&& pulseOnNotificationAvailable();
}
- /** {@hide} */
+ /** @hide */
public boolean pulseOnNotificationAvailable() {
return ambientDisplayAvailable();
}
- /** {@hide} */
+ /** @hide */
public boolean pickupGestureEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_PICK_UP_GESTURE, user)
&& dozePickupSensorAvailable();
}
- /** {@hide} */
+ /** @hide */
public boolean dozePickupSensorAvailable() {
return mContext.getResources().getBoolean(R.bool.config_dozePulsePickup);
}
- /** {@hide} */
+ /** @hide */
public boolean tapGestureEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_TAP_SCREEN_GESTURE, user)
&& tapSensorAvailable();
}
- /** {@hide} */
+ /** @hide */
public boolean tapSensorAvailable() {
for (String tapType : tapSensorTypeMapping()) {
if (!TextUtils.isEmpty(tapType)) {
@@ -96,18 +119,18 @@ public class AmbientDisplayConfiguration {
return false;
}
- /** {@hide} */
+ /** @hide */
public boolean doubleTapGestureEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, user)
&& doubleTapSensorAvailable();
}
- /** {@hide} */
+ /** @hide */
public boolean doubleTapSensorAvailable() {
return !TextUtils.isEmpty(doubleTapSensorType());
}
- /** {@hide} */
+ /** @hide */
public boolean quickPickupSensorEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_QUICK_PICKUP_GESTURE, user)
&& !TextUtils.isEmpty(quickPickupSensorType())
@@ -115,41 +138,41 @@ public class AmbientDisplayConfiguration {
&& !alwaysOnEnabled(user);
}
- /** {@hide} */
+ /** @hide */
public boolean screenOffUdfpsEnabled(int user) {
return !TextUtils.isEmpty(udfpsLongPressSensorType())
&& boolSettingDefaultOff("screen_off_udfps_enabled", user);
}
- /** {@hide} */
+ /** @hide */
public boolean wakeScreenGestureAvailable() {
return mContext.getResources()
.getBoolean(R.bool.config_dozeWakeLockScreenSensorAvailable);
}
- /** {@hide} */
+ /** @hide */
public boolean wakeLockScreenGestureEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, user)
&& wakeScreenGestureAvailable();
}
- /** {@hide} */
+ /** @hide */
public boolean wakeDisplayGestureEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE, user)
&& wakeScreenGestureAvailable();
}
- /** {@hide} */
+ /** @hide */
public long getWakeLockScreenDebounce() {
return mContext.getResources().getInteger(R.integer.config_dozeWakeLockScreenDebounce);
}
- /** {@hide} */
+ /** @hide */
public String doubleTapSensorType() {
return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType);
}
- /** {@hide}
+ /** @hide
* May support multiple postures.
*/
public String[] tapSensorTypeMapping() {
@@ -163,22 +186,22 @@ public class AmbientDisplayConfiguration {
return postureMapping;
}
- /** {@hide} */
+ /** @hide */
public String longPressSensorType() {
return mContext.getResources().getString(R.string.config_dozeLongPressSensorType);
}
- /** {@hide} */
+ /** @hide */
public String udfpsLongPressSensorType() {
return mContext.getResources().getString(R.string.config_dozeUdfpsLongPressSensorType);
}
- /** {@hide} */
+ /** @hide */
public String quickPickupSensorType() {
return mContext.getResources().getString(R.string.config_quickPickupSensorType);
}
- /** {@hide} */
+ /** @hide */
public boolean pulseOnLongPressEnabled(int user) {
return pulseOnLongPressAvailable() && boolSettingDefaultOff(
Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, user);
@@ -191,7 +214,7 @@ public class AmbientDisplayConfiguration {
/**
* Returns if Always-on-Display functionality is enabled on the display for a specified user.
*
- * {@hide}
+ * @hide
*/
@TestApi
public boolean alwaysOnEnabled(int user) {
@@ -202,7 +225,7 @@ public class AmbientDisplayConfiguration {
/**
* Returns if Always-on-Display functionality is available on the display.
*
- * {@hide}
+ * @hide
*/
@TestApi
public boolean alwaysOnAvailable() {
@@ -213,29 +236,29 @@ public class AmbientDisplayConfiguration {
/**
* Returns if Always-on-Display functionality is available on the display for a specified user.
*
- * {@hide}
+ * @hide
*/
@TestApi
public boolean alwaysOnAvailableForUser(int user) {
return alwaysOnAvailable() && !accessibilityInversionEnabled(user);
}
- /** {@hide} */
+ /** @hide */
public String ambientDisplayComponent() {
return mContext.getResources().getString(R.string.config_dozeComponent);
}
- /** {@hide} */
+ /** @hide */
public boolean accessibilityInversionEnabled(int user) {
return boolSettingDefaultOff(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, user);
}
- /** {@hide} */
+ /** @hide */
public boolean ambientDisplayAvailable() {
return !TextUtils.isEmpty(ambientDisplayComponent());
}
- /** {@hide} */
+ /** @hide */
public boolean dozeSuppressed(int user) {
return boolSettingDefaultOff(Settings.Secure.SUPPRESS_DOZE, user);
}
@@ -259,4 +282,52 @@ public class AmbientDisplayConfiguration {
private boolean boolSetting(String name, int user, int def) {
return Settings.Secure.getIntForUser(mContext.getContentResolver(), name, def, user) != 0;
}
+
+ /** @hide */
+ @TestApi
+ public void disableDozeSettings(int userId) {
+ disableDozeSettings(false /* shouldDisableNonUserConfigurable */, userId);
+ }
+
+ /** @hide */
+ @TestApi
+ public void disableDozeSettings(boolean shouldDisableNonUserConfigurable, int userId) {
+ Map<String, String> initialValues = mUsersInitialValues.get(userId);
+ if (initialValues != null && !initialValues.isEmpty()) {
+ throw new IllegalStateException("Don't call #disableDozeSettings more than once,"
+ + "without first calling #restoreDozeSettings");
+ }
+ initialValues = new ArrayMap<>();
+ for (String name : DOZE_SETTINGS) {
+ initialValues.put(name, getDozeSetting(name, userId));
+ putDozeSetting(name, "0", userId);
+ }
+ if (shouldDisableNonUserConfigurable) {
+ for (String name : NON_USER_CONFIGURABLE_DOZE_SETTINGS) {
+ initialValues.put(name, getDozeSetting(name, userId));
+ putDozeSetting(name, "0", userId);
+ }
+ }
+ mUsersInitialValues.put(userId, initialValues);
+ }
+
+ /** @hide */
+ @TestApi
+ public void restoreDozeSettings(int userId) {
+ final Map<String, String> initialValues = mUsersInitialValues.get(userId);
+ if (initialValues != null && !initialValues.isEmpty()) {
+ for (String name : DOZE_SETTINGS) {
+ putDozeSetting(name, initialValues.get(name), userId);
+ }
+ mUsersInitialValues.remove(userId);
+ }
+ }
+
+ private String getDozeSetting(String name, int userId) {
+ return Settings.Secure.getStringForUser(mContext.getContentResolver(), name, userId);
+ }
+
+ private void putDozeSetting(String name, String value, int userId) {
+ Settings.Secure.putStringForUser(mContext.getContentResolver(), name, value, userId);
+ }
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 29221b801ef6..6d2cdf3cfadc 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -594,8 +594,16 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
mAuthenticationCallback = callback;
mCryptoObject = crypto;
final long operationId = crypto != null ? crypto.getOpId() : 0;
- final long authId = mService.authenticate(mToken, operationId, sensorId, userId,
- mServiceReceiver, mContext.getOpPackageName(), ignoreEnrollmentState);
+ final long authId =
+ mService.authenticate(
+ mToken,
+ operationId,
+ sensorId,
+ userId,
+ mServiceReceiver,
+ mContext.getOpPackageName(),
+ mContext.getAttributionTag(),
+ ignoreEnrollmentState);
if (cancel != null) {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
}
@@ -838,7 +846,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public List<Fingerprint> getEnrolledFingerprints(int userId) {
if (mService != null) try {
- return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
+ return mService.getEnrolledFingerprints(
+ userId, mContext.getOpPackageName(), mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -997,7 +1006,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
INTERACT_ACROSS_USERS})
public boolean hasEnrolledFingerprints(int userId) {
if (mService != null) try {
- return mService.hasEnrolledFingerprintsDeprecated(userId, mContext.getOpPackageName());
+ return mService.hasEnrolledFingerprintsDeprecated(
+ userId, mContext.getOpPackageName(), mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1021,7 +1031,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
if (mService != null) {
try {
- return mService.isHardwareDetectedDeprecated(mContext.getOpPackageName());
+ return mService.isHardwareDetectedDeprecated(
+ mContext.getOpPackageName(), mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1331,7 +1342,11 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
private void cancelAuthentication(long requestId) {
if (mService != null) try {
- mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
+ mService.cancelAuthentication(
+ mToken,
+ mContext.getOpPackageName(),
+ mContext.getAttributionTag(),
+ requestId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 12114aa3fa33..d60bb6ef1543 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -52,7 +52,7 @@ interface IFingerprintService {
// permission. This is effectively deprecated, since it only comes through FingerprintManager
// now. A requestId is returned that can be used to cancel this operation.
long authenticate(IBinder token, long operationId, int sensorId, int userId,
- IFingerprintServiceReceiver receiver, String opPackageName,
+ IFingerprintServiceReceiver receiver, String opPackageName, String attributionTag,
boolean shouldIgnoreEnrollmentState);
// Uses the fingerprint hardware to detect for the presence of a finger, without giving details
@@ -74,7 +74,7 @@ interface IFingerprintService {
void startPreparedClient(int sensorId, int cookie);
// Cancel authentication for the given requestId.
- void cancelAuthentication(IBinder token, String opPackageName, long requestId);
+ void cancelAuthentication(IBinder token, String opPackageName, String attributionTag, long requestId);
// Cancel finger detection for the given requestId.
void cancelFingerprintDetect(IBinder token, String opPackageName, long requestId);
@@ -101,10 +101,10 @@ interface IFingerprintService {
void rename(int fingerId, int userId, String name);
// Get a list of enrolled fingerprints in the given userId.
- List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName);
+ List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName, String attributionTag);
// Determine if the HAL is loaded and ready. Meant to support the deprecated FingerprintManager APIs
- boolean isHardwareDetectedDeprecated(String opPackageName);
+ boolean isHardwareDetectedDeprecated(String opPackageName, String attributionTag);
// Determine if the specified HAL is loaded and ready
boolean isHardwareDetected(int sensorId, String opPackageName);
@@ -116,7 +116,7 @@ interface IFingerprintService {
void revokeChallenge(IBinder token, int sensorId, int userId, String opPackageName, long challenge);
// Determine if a user has at least one enrolled fingerprint. Meant to support the deprecated FingerprintManager APIs
- boolean hasEnrolledFingerprintsDeprecated(int userId, String opPackageName);
+ boolean hasEnrolledFingerprintsDeprecated(int userId, String opPackageName, String attributionTag);
// Determine if a user has at least one enrolled fingerprint.
boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName);
diff --git a/core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl b/core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl
index 69f29111635c..b2ddef9c29a6 100644
--- a/core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl
@@ -22,6 +22,8 @@ import android.hardware.hdmi.HdmiDeviceInfo;
* Callback interface definition for HDMI client to get informed of
* the CEC logical device status change event.
*
+ * Only to be used on TV panel and Audio System devices (b/226317598).
+ *
* @hide
*/
oneway interface IHdmiDeviceEventListener {
diff --git a/core/java/android/hardware/location/OWNERS b/core/java/android/hardware/location/OWNERS
index bd40409f71c6..747f90947b9c 100644
--- a/core/java/android/hardware/location/OWNERS
+++ b/core/java/android/hardware/location/OWNERS
@@ -1,9 +1,12 @@
# Bug component: 880425
+dnchrist@google.com
+etn@google.com
+lifu@google.com
mstogaitis@google.com
+sooniln@google.com
wyattriley@google.com
-etn@google.com
-weiwa@google.com
+yuhany@google.com
# ContextHub team
per-file *ContextHub*,*NanoApp* = file:platform/system/chre:/OWNERS
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 7ff74c68fc53..4fb6abdae5ff 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -17,6 +17,8 @@
package android.hardware.usb;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
+
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.LongDef;
@@ -36,8 +38,6 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.hardware.usb.gadget.V1_0.GadgetFunction;
import android.hardware.usb.gadget.V1_2.UsbSpeed;
-import android.hardware.usb.IUsbOperationInternal;
-import android.hardware.usb.UsbPort;
import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
@@ -1189,9 +1189,8 @@ public class UsbManager {
/**
* Enable/Disable the USB data signaling.
* <p>
- * Enables/Disables USB data path of the first port..
+ * Enables/Disables USB data path of all USB ports.
* It will force to stop or restore USB data signaling.
- * Call UsbPort API if the device has more than one UsbPort.
* </p>
*
* @param enable enable or disable USB data signaling
@@ -1202,11 +1201,30 @@ public class UsbManager {
*/
@RequiresPermission(Manifest.permission.MANAGE_USB)
public boolean enableUsbDataSignal(boolean enable) {
- List<UsbPort> usbPorts = getPorts();
- if (usbPorts.size() == 1) {
- return usbPorts.get(0).enableUsbData(enable) == UsbPort.ENABLE_USB_DATA_SUCCESS;
+ return setUsbDataSignal(getPorts(), !enable, /* revertOnFailure= */ true);
+ }
+
+ private boolean setUsbDataSignal(List<UsbPort> usbPorts, boolean disable,
+ boolean revertOnFailure) {
+ List<UsbPort> changedPorts = new ArrayList<>();
+ for (int i = 0; i < usbPorts.size(); i++) {
+ UsbPort port = usbPorts.get(i);
+ if (isPortDisabled(port) != disable) {
+ changedPorts.add(port);
+ if (port.enableUsbData(!disable) != UsbPort.ENABLE_USB_DATA_SUCCESS
+ && revertOnFailure) {
+ Log.e(TAG, "Failed to set usb data signal for portID(" + port.getId() + ")");
+ setUsbDataSignal(changedPorts, !disable, /* revertOnFailure= */ false);
+ return false;
+ }
+ }
}
- return false;
+ return true;
+ }
+
+ private boolean isPortDisabled(UsbPort usbPort) {
+ return (getPortStatus(usbPort).getUsbDataStatus() & DATA_STATUS_DISABLED_FORCE)
+ == DATA_STATUS_DISABLED_FORCE;
}
/**
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 8e5ed8f6e578..1f3108a1f04b 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -66,3 +66,6 @@ per-file *UpdateEngine* = file:/platform/system/update_engine:/OWNERS
# VINTF
per-file Vintf* = file:/platform/system/libvintf:/OWNERS
+
+# Tracing
+per-file Trace.java = file:/TRACE_OWNERS
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 978e99d6c5c5..2664f05a9664 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -549,6 +549,7 @@ public final class Parcel {
*/
public final void recycle() {
if (DEBUG_RECYCLE) mStack = null;
+ mClassCookies = null;
freeBuffer();
if (mOwnsNativeParcelObject) {
@@ -2172,7 +2173,7 @@ public final class Parcel {
* sized with the exact size of dimensions.
*
* @see #readFixedArray
- * @see #createFixedArray
+ * @see #createFixedArray createFixedArray(Class&lt;T&gt;, Parcelable.Creator&lt;S&gt;, int...)
* @see #writeBooleanArray
* @see #writeByteArray
* @see #writeCharArray
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index e3be4d32a014..8f2d218a20c1 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -566,7 +566,8 @@ public final class PowerManager {
WAKE_REASON_HDMI,
WAKE_REASON_DISPLAY_GROUP_ADDED,
WAKE_REASON_DISPLAY_GROUP_TURNED_ON,
- WAKE_REASON_UNFOLD_DEVICE
+ WAKE_REASON_UNFOLD_DEVICE,
+ WAKE_REASON_DREAM_FINISHED
})
@Retention(RetentionPolicy.SOURCE)
public @interface WakeReason{}
@@ -673,6 +674,12 @@ public final class PowerManager {
public static final int WAKE_REASON_UNFOLD_DEVICE = 12;
/**
+ * Wake up reason code: Waking the device due to the dream finishing.
+ * @hide
+ */
+ public static final int WAKE_REASON_DREAM_FINISHED = 13;
+
+ /**
* Convert the wake reason to a string for debugging purposes.
* @hide
*/
@@ -691,6 +698,7 @@ public final class PowerManager {
case WAKE_REASON_DISPLAY_GROUP_ADDED: return "WAKE_REASON_DISPLAY_GROUP_ADDED";
case WAKE_REASON_DISPLAY_GROUP_TURNED_ON: return "WAKE_REASON_DISPLAY_GROUP_TURNED_ON";
case WAKE_REASON_UNFOLD_DEVICE: return "WAKE_REASON_UNFOLD_DEVICE";
+ case WAKE_REASON_DREAM_FINISHED: return "WAKE_REASON_DREAM_FINISHED";
default: return Integer.toString(wakeReason);
}
}
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index a4f6004a288a..ac2156e9e46e 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -136,6 +136,12 @@ public final class Trace {
@FastNative
private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
@FastNative
+ private static native void nativeAsyncTraceForTrackBegin(long tag,
+ String trackName, String name, int cookie);
+ @FastNative
+ private static native void nativeAsyncTraceForTrackEnd(long tag,
+ String trackName, String name, int cookie);
+ @FastNative
private static native void nativeInstant(long tag, String name);
@FastNative
private static native void nativeInstantForTrack(long tag, String trackName, String name);
@@ -271,6 +277,47 @@ public final class Trace {
}
}
+
+ /**
+ * Writes a trace message to indicate that a given section of code has
+ * begun. Must be followed by a call to {@link #asyncTraceForTrackEnd} using the same
+ * tag. This function operates exactly like {@link #asyncTraceBegin(long, String, int)},
+ * except with the inclusion of a track name argument for where this method should appear.
+ *
+ * @param traceTag The trace tag.
+ * @param trackName The track where the event should appear in the trace.
+ * @param methodName The method name to appear in the trace.
+ * @param cookie Unique identifier for distinguishing simultaneous events
+ *
+ * @hide
+ */
+ public static void asyncTraceForTrackBegin(long traceTag,
+ @NonNull String trackName, @NonNull String methodName, int cookie) {
+ if (isTagEnabled(traceTag)) {
+ nativeAsyncTraceForTrackBegin(traceTag, trackName, methodName, cookie);
+ }
+ }
+
+ /**
+ * Writes a trace message to indicate that the current method has ended.
+ * Must be called exactly once for each call to
+ * {@link #asyncTraceForTrackBegin(long, String, String, int)}
+ * using the same tag, track name, name and cookie.
+ *
+ * @param traceTag The trace tag.
+ * @param trackName The track where the event should appear in the trace.
+ * @param methodName The method name to appear in the trace.
+ * @param cookie Unique identifier for distinguishing simultaneous events
+ *
+ * @hide
+ */
+ public static void asyncTraceForTrackEnd(long traceTag,
+ @NonNull String trackName, @NonNull String methodName, int cookie) {
+ if (isTagEnabled(traceTag)) {
+ nativeAsyncTraceForTrackEnd(traceTag, trackName, methodName, cookie);
+ }
+ }
+
/**
* Writes a trace message to indicate that a given section of code was invoked.
*
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index d3d38744a1a9..da9d23b5303a 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -91,6 +91,15 @@ interface IPrintManager {
void setPrintServiceEnabled(in ComponentName service, boolean isEnabled, int userId);
/**
+ * Checks whether the given print service is enabled.
+ *
+ * @param service the service to check
+ * @param userId the id of the user requesting the check
+ * @return whether the given print service is enabled
+ */
+ boolean isPrintServiceEnabled(in ComponentName service, int userId);
+
+ /**
* Listen for changes to the print service recommendations.
*
* @param listener the listener to add
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 9abce5d46ac6..a5e2f33d4418 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -785,6 +785,25 @@ public final class PrintManager {
}
/**
+ * Checks whether a given print service is enabled. The provided service must share UID
+ * with the calling package, otherwise a {@link SecurityException} is thrown.
+ *
+ * @return true if the given print service is enabled
+ */
+ public boolean isPrintServiceEnabled(@NonNull ComponentName service) {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return false;
+ }
+ try {
+ return mService.isPrintServiceEnabled(service, mUserId);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sampling enabled/disabled " + service, re);
+ return false;
+ }
+ }
+
+ /**
* @hide
*/
public static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6e6581790649..d8d9c7fc259e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7230,6 +7230,13 @@ public final class Settings {
*/
public static final String LOCATION_SHOW_SYSTEM_OPS = "locationShowSystemOps";
+
+ /**
+ * Whether or not an indicator experiment has started.
+ * @hide
+ */
+ public static final String LOCATION_INDICATOR_EXPERIMENT_STARTED =
+ "locationIndicatorExperimentStarted";
/**
* A flag containing settings used for biometric weak
* @hide
@@ -10283,10 +10290,18 @@ public final class Settings {
* The strategy used for generating the tonal palettes can be defined with the
* {@code android.theme.customization.theme_style} key, with one of the following options:
* <ul>
- * <li> TONAL_SPOT = Default Material You theme since Android S.</li>
- * <li> VIBRANT = Theme where accent 2 and 3 are analogous to accent 1.</li>
- * <li> EXPRESSIVE = Highly chromatic theme.</li>
- * <li> SPRITZ = Desaturated theme, almost greyscale.</li>
+ * <li> {@code TONAL_SPOT} is a mid vibrancy palette that uses an accent 3 analogous to
+ * accent 1.</li>
+ * <li> {@code VIBRANT} is a high vibrancy palette that harmoniously blends subtle shifts
+ * between colors.</li>
+ * <li> {@code EXPRESSIVE} is a high vibrancy palette that pairs unexpected and unique
+ * accents colors together.</li>
+ * <li> {@code SPRITZ} is a low vibrancy palette that creates a soft wash between
+ * colors.</li>
+ * <li> {@code RAINBOW} uses both chromatic accents and neutral surfaces to create a more
+ * subtle color experience for users.</li>
+ * <li> {@code FRUIT_SALAD} experiments with the concept of "two tone colors" to give
+ * users more expression.</li>
* </ul>
*
* Example of valid fabricated theme specification:
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 431a88d324d8..1507c87c0452 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -105,6 +105,12 @@ public final class FillRequest implements Parcelable {
*/
public static final @RequestFlags int FLAG_SUPPORTS_FILL_DIALOG = 0x40;
+ /**
+ * Indicates the ime is showing while request coming.
+ * @hide
+ */
+ public static final @RequestFlags int FLAG_IME_SHOWING = 0x80;
+
/** @hide */
public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
@@ -201,7 +207,8 @@ public final class FillRequest implements Parcelable {
FLAG_COMPATIBILITY_MODE_REQUEST,
FLAG_PASSWORD_INPUT_TYPE,
FLAG_VIEW_NOT_FOCUSED,
- FLAG_SUPPORTS_FILL_DIALOG
+ FLAG_SUPPORTS_FILL_DIALOG,
+ FLAG_IME_SHOWING
})
@Retention(RetentionPolicy.SOURCE)
@DataClass.Generated.Member
@@ -227,6 +234,8 @@ public final class FillRequest implements Parcelable {
return "FLAG_VIEW_NOT_FOCUSED";
case FLAG_SUPPORTS_FILL_DIALOG:
return "FLAG_SUPPORTS_FILL_DIALOG";
+ case FLAG_IME_SHOWING:
+ return "FLAG_IME_SHOWING";
default: return Integer.toHexString(value);
}
}
@@ -302,7 +311,8 @@ public final class FillRequest implements Parcelable {
| FLAG_COMPATIBILITY_MODE_REQUEST
| FLAG_PASSWORD_INPUT_TYPE
| FLAG_VIEW_NOT_FOCUSED
- | FLAG_SUPPORTS_FILL_DIALOG);
+ | FLAG_SUPPORTS_FILL_DIALOG
+ | FLAG_IME_SHOWING);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
this.mDelayedFillIntentSender = delayedFillIntentSender;
@@ -462,7 +472,8 @@ public final class FillRequest implements Parcelable {
| FLAG_COMPATIBILITY_MODE_REQUEST
| FLAG_PASSWORD_INPUT_TYPE
| FLAG_VIEW_NOT_FOCUSED
- | FLAG_SUPPORTS_FILL_DIALOG);
+ | FLAG_SUPPORTS_FILL_DIALOG
+ | FLAG_IME_SHOWING);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
this.mDelayedFillIntentSender = delayedFillIntentSender;
@@ -484,10 +495,10 @@ public final class FillRequest implements Parcelable {
};
@DataClass.Generated(
- time = 1647644111186L,
+ time = 1647856966565L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
- inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/speech/RecognitionSupport.java b/core/java/android/speech/RecognitionSupport.java
index 60c3b63e80c0..336645c5a0a2 100644
--- a/core/java/android/speech/RecognitionSupport.java
+++ b/core/java/android/speech/RecognitionSupport.java
@@ -36,37 +36,6 @@ import java.util.List;
)
public final class RecognitionSupport implements Parcelable {
- /**
- * Support for this request is ready for use on this device for the returned languages.
- *
- * @deprecated See {@link #getInstalledOnDeviceLanguages()}.
- */
- @NonNull
- @Deprecated
- @DataClass.PluralOf("installedLanguage")
- private List<String> mInstalledLanguages = List.of();
-
- /**
- * Support for this request is scheduled for download for the returned languages.
- *
- * @deprecated See {@link #getPendingOnDeviceLanguages()}.
- */
- @NonNull
- @Deprecated
- @DataClass.PluralOf("pendingLanguage")
- private List<String> mPendingLanguages = List.of();
-
- /**
- * These languages are supported but need to be downloaded before use. See {@link
- * SpeechRecognizer#triggerModelDownload(Intent)}.
- *
- * @deprecated See {@link #getSupportedOnDeviceLanguages()}.
- */
- @NonNull
- @Deprecated
- @DataClass.PluralOf("supportedLanguage")
- private List<String> mSupportedLanguages = List.of();
-
/** Support for this request is ready for use on this device for the returned languages. */
@NonNull
@DataClass.PluralOf("installedOnDeviceLanguage")
@@ -111,28 +80,10 @@ public final class RecognitionSupport implements Parcelable {
@DataClass.Generated.Member
/* package-private */ RecognitionSupport(
- @NonNull @Deprecated List<String> installedLanguages,
- @NonNull @Deprecated List<String> pendingLanguages,
- @NonNull @Deprecated List<String> supportedLanguages,
@NonNull List<String> installedOnDeviceLanguages,
@NonNull List<String> pendingOnDeviceLanguages,
@NonNull List<String> supportedOnDeviceLanguages,
@NonNull List<String> onlineLanguages) {
- this.mInstalledLanguages = installedLanguages;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mInstalledLanguages);
- com.android.internal.util.AnnotationValidations.validate(
- Deprecated.class, null, mInstalledLanguages);
- this.mPendingLanguages = pendingLanguages;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mPendingLanguages);
- com.android.internal.util.AnnotationValidations.validate(
- Deprecated.class, null, mPendingLanguages);
- this.mSupportedLanguages = supportedLanguages;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mSupportedLanguages);
- com.android.internal.util.AnnotationValidations.validate(
- Deprecated.class, null, mSupportedLanguages);
this.mInstalledOnDeviceLanguages = installedOnDeviceLanguages;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mInstalledOnDeviceLanguages);
@@ -151,37 +102,6 @@ public final class RecognitionSupport implements Parcelable {
/**
* Support for this request is ready for use on this device for the returned languages.
- *
- * @deprecated See {@link #getInstalledOnDeviceLanguages()}.
- */
- @DataClass.Generated.Member
- @NonNull @Deprecated public List<String> getInstalledLanguages() {
- return mInstalledLanguages;
- }
-
- /**
- * Support for this request is scheduled for download for the returned languages.
- *
- * @deprecated See {@link #getPendingOnDeviceLanguages()}.
- */
- @DataClass.Generated.Member
- @NonNull @Deprecated public List<String> getPendingLanguages() {
- return mPendingLanguages;
- }
-
- /**
- * These languages are supported but need to be downloaded before use. See {@link
- * SpeechRecognizer#triggerModelDownload(Intent)}.
- *
- * @deprecated See {@link #getSupportedOnDeviceLanguages()}.
- */
- @DataClass.Generated.Member
- @NonNull @Deprecated public List<String> getSupportedLanguages() {
- return mSupportedLanguages;
- }
-
- /**
- * Support for this request is ready for use on this device for the returned languages.
*/
@DataClass.Generated.Member
public @NonNull List<String> getInstalledOnDeviceLanguages() {
@@ -222,9 +142,6 @@ public final class RecognitionSupport implements Parcelable {
// String fieldNameToString() { ... }
return "RecognitionSupport { " +
- "installedLanguages = " + mInstalledLanguages + ", " +
- "pendingLanguages = " + mPendingLanguages + ", " +
- "supportedLanguages = " + mSupportedLanguages + ", " +
"installedOnDeviceLanguages = " + mInstalledOnDeviceLanguages + ", " +
"pendingOnDeviceLanguages = " + mPendingOnDeviceLanguages + ", " +
"supportedOnDeviceLanguages = " + mSupportedOnDeviceLanguages + ", " +
@@ -245,9 +162,6 @@ public final class RecognitionSupport implements Parcelable {
RecognitionSupport that = (RecognitionSupport) o;
//noinspection PointlessBooleanExpression
return true
- && java.util.Objects.equals(mInstalledLanguages, that.mInstalledLanguages)
- && java.util.Objects.equals(mPendingLanguages, that.mPendingLanguages)
- && java.util.Objects.equals(mSupportedLanguages, that.mSupportedLanguages)
&& java.util.Objects.equals(mInstalledOnDeviceLanguages, that.mInstalledOnDeviceLanguages)
&& java.util.Objects.equals(mPendingOnDeviceLanguages, that.mPendingOnDeviceLanguages)
&& java.util.Objects.equals(mSupportedOnDeviceLanguages, that.mSupportedOnDeviceLanguages)
@@ -261,9 +175,6 @@ public final class RecognitionSupport implements Parcelable {
// int fieldNameHashCode() { ... }
int _hash = 1;
- _hash = 31 * _hash + java.util.Objects.hashCode(mInstalledLanguages);
- _hash = 31 * _hash + java.util.Objects.hashCode(mPendingLanguages);
- _hash = 31 * _hash + java.util.Objects.hashCode(mSupportedLanguages);
_hash = 31 * _hash + java.util.Objects.hashCode(mInstalledOnDeviceLanguages);
_hash = 31 * _hash + java.util.Objects.hashCode(mPendingOnDeviceLanguages);
_hash = 31 * _hash + java.util.Objects.hashCode(mSupportedOnDeviceLanguages);
@@ -277,9 +188,6 @@ public final class RecognitionSupport implements Parcelable {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
- dest.writeStringList(mInstalledLanguages);
- dest.writeStringList(mPendingLanguages);
- dest.writeStringList(mSupportedLanguages);
dest.writeStringList(mInstalledOnDeviceLanguages);
dest.writeStringList(mPendingOnDeviceLanguages);
dest.writeStringList(mSupportedOnDeviceLanguages);
@@ -297,12 +205,6 @@ public final class RecognitionSupport implements Parcelable {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
- List<String> installedLanguages = new java.util.ArrayList<>();
- in.readStringList(installedLanguages);
- List<String> pendingLanguages = new java.util.ArrayList<>();
- in.readStringList(pendingLanguages);
- List<String> supportedLanguages = new java.util.ArrayList<>();
- in.readStringList(supportedLanguages);
List<String> installedOnDeviceLanguages = new java.util.ArrayList<>();
in.readStringList(installedOnDeviceLanguages);
List<String> pendingOnDeviceLanguages = new java.util.ArrayList<>();
@@ -312,21 +214,6 @@ public final class RecognitionSupport implements Parcelable {
List<String> onlineLanguages = new java.util.ArrayList<>();
in.readStringList(onlineLanguages);
- this.mInstalledLanguages = installedLanguages;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mInstalledLanguages);
- com.android.internal.util.AnnotationValidations.validate(
- Deprecated.class, null, mInstalledLanguages);
- this.mPendingLanguages = pendingLanguages;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mPendingLanguages);
- com.android.internal.util.AnnotationValidations.validate(
- Deprecated.class, null, mPendingLanguages);
- this.mSupportedLanguages = supportedLanguages;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mSupportedLanguages);
- com.android.internal.util.AnnotationValidations.validate(
- Deprecated.class, null, mSupportedLanguages);
this.mInstalledOnDeviceLanguages = installedOnDeviceLanguages;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mInstalledOnDeviceLanguages);
@@ -364,9 +251,6 @@ public final class RecognitionSupport implements Parcelable {
@DataClass.Generated.Member
public static final class Builder {
- private @NonNull @Deprecated List<String> mInstalledLanguages;
- private @NonNull @Deprecated List<String> mPendingLanguages;
- private @NonNull @Deprecated List<String> mSupportedLanguages;
private @NonNull List<String> mInstalledOnDeviceLanguages;
private @NonNull List<String> mPendingOnDeviceLanguages;
private @NonNull List<String> mSupportedOnDeviceLanguages;
@@ -379,81 +263,11 @@ public final class RecognitionSupport implements Parcelable {
/**
* Support for this request is ready for use on this device for the returned languages.
- *
- * @deprecated See {@link #getInstalledOnDeviceLanguages()}.
- */
- @DataClass.Generated.Member
- @Deprecated @NonNull
- public Builder setInstalledLanguages(@NonNull @Deprecated List<String> value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x1;
- mInstalledLanguages = value;
- return this;
- }
-
- /** @see #setInstalledLanguages */
- @DataClass.Generated.Member
- @Deprecated @NonNull
- public Builder addInstalledLanguage(@NonNull String value) {
- if (mInstalledLanguages == null) setInstalledLanguages(new java.util.ArrayList<>());
- mInstalledLanguages.add(value);
- return this;
- }
-
- /**
- * Support for this request is scheduled for download for the returned languages.
- *
- * @deprecated See {@link #getPendingOnDeviceLanguages()}.
- */
- @DataClass.Generated.Member
- @Deprecated @NonNull
- public Builder setPendingLanguages(@NonNull @Deprecated List<String> value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x2;
- mPendingLanguages = value;
- return this;
- }
-
- /** @see #setPendingLanguages */
- @DataClass.Generated.Member
- @Deprecated @NonNull
- public Builder addPendingLanguage(@NonNull String value) {
- if (mPendingLanguages == null) setPendingLanguages(new java.util.ArrayList<>());
- mPendingLanguages.add(value);
- return this;
- }
-
- /**
- * These languages are supported but need to be downloaded before use. See {@link
- * SpeechRecognizer#triggerModelDownload(Intent)}.
- *
- * @deprecated See {@link #getSupportedOnDeviceLanguages()}.
- */
- @DataClass.Generated.Member
- @Deprecated @NonNull
- public Builder setSupportedLanguages(@NonNull @Deprecated List<String> value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x4;
- mSupportedLanguages = value;
- return this;
- }
-
- /** @see #setSupportedLanguages */
- @DataClass.Generated.Member
- @Deprecated @NonNull
- public Builder addSupportedLanguage(@NonNull String value) {
- if (mSupportedLanguages == null) setSupportedLanguages(new java.util.ArrayList<>());
- mSupportedLanguages.add(value);
- return this;
- }
-
- /**
- * Support for this request is ready for use on this device for the returned languages.
*/
@DataClass.Generated.Member
public @NonNull Builder setInstalledOnDeviceLanguages(@NonNull List<String> value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x8;
+ mBuilderFieldsSet |= 0x1;
mInstalledOnDeviceLanguages = value;
return this;
}
@@ -472,7 +286,7 @@ public final class RecognitionSupport implements Parcelable {
@DataClass.Generated.Member
public @NonNull Builder setPendingOnDeviceLanguages(@NonNull List<String> value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x10;
+ mBuilderFieldsSet |= 0x2;
mPendingOnDeviceLanguages = value;
return this;
}
@@ -492,7 +306,7 @@ public final class RecognitionSupport implements Parcelable {
@DataClass.Generated.Member
public @NonNull Builder setSupportedOnDeviceLanguages(@NonNull List<String> value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x20;
+ mBuilderFieldsSet |= 0x4;
mSupportedOnDeviceLanguages = value;
return this;
}
@@ -513,7 +327,7 @@ public final class RecognitionSupport implements Parcelable {
@DataClass.Generated.Member
public @NonNull Builder setOnlineLanguages(@NonNull List<String> value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x40;
+ mBuilderFieldsSet |= 0x8;
mOnlineLanguages = value;
return this;
}
@@ -529,33 +343,21 @@ public final class RecognitionSupport implements Parcelable {
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull RecognitionSupport build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x80; // Mark builder used
+ mBuilderFieldsSet |= 0x10; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
- mInstalledLanguages = List.of();
- }
- if ((mBuilderFieldsSet & 0x2) == 0) {
- mPendingLanguages = List.of();
- }
- if ((mBuilderFieldsSet & 0x4) == 0) {
- mSupportedLanguages = List.of();
- }
- if ((mBuilderFieldsSet & 0x8) == 0) {
mInstalledOnDeviceLanguages = List.of();
}
- if ((mBuilderFieldsSet & 0x10) == 0) {
+ if ((mBuilderFieldsSet & 0x2) == 0) {
mPendingOnDeviceLanguages = List.of();
}
- if ((mBuilderFieldsSet & 0x20) == 0) {
+ if ((mBuilderFieldsSet & 0x4) == 0) {
mSupportedOnDeviceLanguages = List.of();
}
- if ((mBuilderFieldsSet & 0x40) == 0) {
+ if ((mBuilderFieldsSet & 0x8) == 0) {
mOnlineLanguages = List.of();
}
RecognitionSupport o = new RecognitionSupport(
- mInstalledLanguages,
- mPendingLanguages,
- mSupportedLanguages,
mInstalledOnDeviceLanguages,
mPendingOnDeviceLanguages,
mSupportedOnDeviceLanguages,
@@ -564,7 +366,7 @@ public final class RecognitionSupport implements Parcelable {
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x80) != 0) {
+ if ((mBuilderFieldsSet & 0x10) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
@@ -572,10 +374,10 @@ public final class RecognitionSupport implements Parcelable {
}
@DataClass.Generated(
- time = 1647890081869L,
+ time = 1648131602084L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/speech/RecognitionSupport.java",
- inputSignatures = "private @android.annotation.NonNull @java.lang.Deprecated @com.android.internal.util.DataClass.PluralOf(\"installedLanguage\") java.util.List<java.lang.String> mInstalledLanguages\nprivate @android.annotation.NonNull @java.lang.Deprecated @com.android.internal.util.DataClass.PluralOf(\"pendingLanguage\") java.util.List<java.lang.String> mPendingLanguages\nprivate @android.annotation.NonNull @java.lang.Deprecated @com.android.internal.util.DataClass.PluralOf(\"supportedLanguage\") java.util.List<java.lang.String> mSupportedLanguages\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"installedOnDeviceLanguage\") java.util.List<java.lang.String> mInstalledOnDeviceLanguages\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"pendingOnDeviceLanguage\") java.util.List<java.lang.String> mPendingOnDeviceLanguages\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"supportedOnDeviceLanguage\") java.util.List<java.lang.String> mSupportedOnDeviceLanguages\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"onlineLanguage\") java.util.List<java.lang.String> mOnlineLanguages\nclass RecognitionSupport extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+ inputSignatures = "private @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"installedOnDeviceLanguage\") java.util.List<java.lang.String> mInstalledOnDeviceLanguages\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"pendingOnDeviceLanguage\") java.util.List<java.lang.String> mPendingOnDeviceLanguages\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"supportedOnDeviceLanguage\") java.util.List<java.lang.String> mSupportedOnDeviceLanguages\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"onlineLanguage\") java.util.List<java.lang.String> mOnlineLanguages\nclass RecognitionSupport extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/util/SparseSetArray.java b/core/java/android/util/SparseSetArray.java
index f5025f7a9e99..eb53b425a228 100644
--- a/core/java/android/util/SparseSetArray.java
+++ b/core/java/android/util/SparseSetArray.java
@@ -21,9 +21,26 @@ package android.util;
* @hide
*/
public class SparseSetArray<T> {
- private final SparseArray<ArraySet<T>> mData = new SparseArray<>();
+ private final SparseArray<ArraySet<T>> mData;
public SparseSetArray() {
+ mData = new SparseArray<>();
+ }
+
+ /**
+ * Copy constructor
+ */
+ public SparseSetArray(SparseSetArray<T> src) {
+ final int arraySize = src.size();
+ mData = new SparseArray<>(arraySize);
+ for (int i = 0; i < arraySize; i++) {
+ final int key = src.keyAt(i);
+ final ArraySet<T> set = src.get(key);
+ final int setSize = set.size();
+ for (int j = 0; j < setSize; j++) {
+ add(key, set.valueAt(j));
+ }
+ }
}
/**
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index 3e2849012b2b..f844fddedc98 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -10,6 +10,7 @@ ogunwale@google.com
jjaggi@google.com
roosa@google.com
jreck@google.com
+siyamed@google.com
# Autofill
per-file ViewStructure.java = file:/core/java/android/service/autofill/OWNERS
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index b55ae1e7e468..15e0cce9af10 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -41,6 +41,43 @@ import android.util.Log;
* <p>TextureView can only be used in a hardware accelerated window. When
* rendered in software, TextureView will draw nothing.</p>
*
+ * <p><b>TextureView vs. SurfaceView Capabilities</b></p>
+
+ * <p>
+ * <table>
+ * <tr>
+ * <th>&nbsp;</th>
+ * <th style="text-align: center;">TextureView</th>
+ * <th style="text-align: center;">SurfaceView</th>
+ * </tr>
+ * <tr>
+ * <td>Supports alpha</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>Supports rotations</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>Supports clipping</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>HDR support</td>
+ * <td style="text-align: center;">Limited (on Android T+)</td>
+ * <td style="text-align: center;">Full</td>
+ * </tr>
+ * <tr>
+ * <td>Renders DRM content</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * <td style="text-align: center;">X</td>
+ * </tr>
+ * </table>
+ * </p>
+ *
* <p>Unlike {@link SurfaceView}, TextureView does not create a separate
* window but behaves as a regular View. This key difference allows a
* TextureView to have translucency, arbitrary rotations, and complex
@@ -51,8 +88,8 @@ import android.util.Log;
* hierarchy is that it may have slower performance than
* SurfaceView. TextureView contents must be copied, internally, from the
* underlying surface into the view displaying those contents. For
- * that reason, SurfaceView is recommended as a more general solution
- * to problems requiring rendering to surfaces.</p>
+ * that reason, <b>SurfaceView is recommended as a more general solution
+ * to problems requiring rendering to surfaces.</b></p>
*
* <p>Using a TextureView is simple: all you need to do is get its
* {@link SurfaceTexture}. The {@link SurfaceTexture} can then be used to
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ac381756d516..931ae2748785 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -278,7 +278,8 @@ public final class ViewRootImpl implements ViewParent,
* Whether the caption is drawn by the shell.
* @hide
*/
- public static final boolean CAPTION_ON_SHELL = false;
+ public static final boolean CAPTION_ON_SHELL =
+ SystemProperties.getBoolean("persist.debug.caption_on_shell", false);
/**
* Whether the client should compute the window frame on its own.
@@ -817,12 +818,7 @@ public final class ViewRootImpl implements ViewParent,
private final SurfaceSyncer mSurfaceSyncer = new SurfaceSyncer();
private int mLastSyncId = -1;
private SurfaceSyncer.SyncBufferCallback mSyncBufferCallback;
-
- /**
- * Keeps track of the last frame number that was attempted to draw. Should only be accessed on
- * the RenderThread.
- */
- private long mRtLastAttemptedDrawFrameNum = 0;
+ private int mNumSyncsInProgress = 0;
private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;
@@ -4250,7 +4246,7 @@ public final class ViewRootImpl implements ViewParent,
mHasPendingTransactions = false;
try {
- boolean canUseAsync = draw(fullRedrawNeeded);
+ boolean canUseAsync = draw(fullRedrawNeeded, usingAsyncReport && mSyncBuffer);
if (usingAsyncReport && !canUseAsync) {
mAttachInfo.mThreadedRenderer.setFrameCallback(null);
usingAsyncReport = false;
@@ -4410,7 +4406,7 @@ public final class ViewRootImpl implements ViewParent,
}
}
- private boolean draw(boolean fullRedrawNeeded) {
+ private boolean draw(boolean fullRedrawNeeded, boolean forceDraw) {
Surface surface = mSurface;
if (!surface.isValid()) {
return false;
@@ -4547,6 +4543,9 @@ public final class ViewRootImpl implements ViewParent,
useAsyncReport = true;
+ if (forceDraw) {
+ mAttachInfo.mThreadedRenderer.forceDrawNextFrame();
+ }
mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
} else {
// If we get here with a disabled & requested hardware renderer, something went
@@ -8095,14 +8094,17 @@ public final class ViewRootImpl implements ViewParent,
private void setFrame(Rect frame) {
mWinFrame.set(frame);
+ final WindowConfiguration winConfig = getConfiguration().windowConfiguration;
+ mPendingBackDropFrame.set(mPendingDragResizing && !winConfig.useWindowFrameForBackdrop()
+ ? winConfig.getMaxBounds()
+ : frame);
// Surface position is now inherited from parent, and BackdropFrameRenderer uses backdrop
// frame to position content. Thus, we just keep the size of backdrop frame, and remove the
// offset to avoid double offset from display origin.
- mPendingBackDropFrame.set(frame);
mPendingBackDropFrame.offsetTo(0, 0);
mInsetsController.onFrameChanged(mOverrideInsetsFrame != null ?
- mOverrideInsetsFrame : frame);
+ mOverrideInsetsFrame : frame);
}
/**
@@ -10870,9 +10872,28 @@ public final class ViewRootImpl implements ViewParent,
});
}
- public final SurfaceSyncer.SyncTarget mSyncTarget = this::readyToSync;
+ public final SurfaceSyncer.SyncTarget mSyncTarget = new SurfaceSyncer.SyncTarget() {
+ @Override
+ public void onReadyToSync(SurfaceSyncer.SyncBufferCallback syncBufferCallback) {
+ readyToSync(syncBufferCallback);
+ }
+
+ @Override
+ public void onSyncComplete() {
+ mHandler.postAtFrontOfQueue(() -> {
+ if (--mNumSyncsInProgress == 0 && mAttachInfo.mThreadedRenderer != null) {
+ HardwareRenderer.setRtAnimationsEnabled(true);
+ }
+ });
+ }
+ };
private void readyToSync(SurfaceSyncer.SyncBufferCallback syncBufferCallback) {
+ mNumSyncsInProgress++;
+ if (mAttachInfo.mThreadedRenderer != null) {
+ HardwareRenderer.setRtAnimationsEnabled(false);
+ }
+
if (mSyncBufferCallback != null) {
Log.d(mTag, "Already set sync for the next draw.");
mSyncBufferCallback.onBufferReady(null);
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index cde1cc704f92..ba3417980a3d 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -517,6 +517,13 @@ public final class WindowInsets {
/**
* Returns the {@link Rect} of the maximum bounds of the system privacy indicator, for the
* current orientation, in relative coordinates, or null if the bounds have not been loaded yet.
+ * <p>
+ * The privacy indicator bounds are determined by SystemUI, and subsequently loaded once the
+ * StatusBar window has been created and attached. The bounds for all rotations are calculated
+ * and loaded at once, and this value is only expected to ever change on display or font scale
+ * changes. As long as there is a StatusBar window, this value should not be expected to be
+ * null.
+ * <p>
* The privacy indicator shows over apps when an app uses the microphone or camera permissions,
* while an app is in immersive mode.
*
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 6fa6d3964ad4..b05b7916d960 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -16,6 +16,7 @@
package android.view.autofill;
+import static android.service.autofill.FillRequest.FLAG_IME_SHOWING;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
@@ -70,6 +71,7 @@ import android.view.ContentInfo;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewRootImpl;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -647,6 +649,9 @@ public final class AutofillManager {
private final boolean mIsFillDialogEnabled;
+ // Indicates whether called the showAutofillDialog() method.
+ private boolean mShowAutofillDialogCalled = false;
+
/** @hide */
public interface AutofillClient {
/**
@@ -1103,6 +1108,14 @@ public final class AutofillManager {
notifyViewEntered(view, flags);
}
+ private int getImeStateFlag(View v) {
+ final WindowInsets rootWindowInsets = v.getRootWindowInsets();
+ if (rootWindowInsets != null && rootWindowInsets.isVisible(WindowInsets.Type.ime())) {
+ return FLAG_IME_SHOWING;
+ }
+ return 0;
+ }
+
@GuardedBy("mLock")
private boolean shouldIgnoreViewEnteredLocked(@NonNull AutofillId id, int flags) {
if (isDisabledByServiceLocked()) {
@@ -1182,6 +1195,8 @@ public final class AutofillManager {
flags |= FLAG_PASSWORD_INPUT_TYPE;
}
+ flags |= getImeStateFlag(view);
+
if (!isActiveLocked()) {
// Starts new session.
startSessionLocked(id, null, value, flags);
@@ -1358,6 +1373,8 @@ public final class AutofillManager {
flags |= FLAG_PASSWORD_INPUT_TYPE;
}
+ flags |= getImeStateFlag(view);
+
if (!isActiveLocked()) {
// Starts new session.
startSessionLocked(id, bounds, null, flags);
@@ -1473,7 +1490,7 @@ public final class AutofillManager {
value = view.getAutofillValue();
}
- updateSessionLocked(id, null, value, ACTION_VALUE_CHANGED, 0);
+ updateSessionLocked(id, null, value, ACTION_VALUE_CHANGED, getImeStateFlag(view));
}
}
@@ -1498,7 +1515,7 @@ public final class AutofillManager {
}
final AutofillId id = getAutofillId(view, virtualId);
- updateSessionLocked(id, null, value, ACTION_VALUE_CHANGED, 0);
+ updateSessionLocked(id, null, value, ACTION_VALUE_CHANGED, getImeStateFlag(view));
}
}
@@ -2057,6 +2074,8 @@ public final class AutofillManager {
mIdShownFillUi = null;
mIsFillRequested = false;
mRequireAutofill = false;
+ mShowAutofillDialogCalled = false;
+ mFillDialogTriggerIds = null;
if (resetEnteredIds) {
mEnteredIds = null;
}
@@ -3051,8 +3070,9 @@ public final class AutofillManager {
* dialog-style UI</a> are available for {@code view}, shows a dialog allowing the user to
* select a suggestion and returns {@code true}.
* <p>
- * The dialog may not be available if the autofill service does not support it, or if the
- * autofill request has not returned a response yet.
+ * The dialog may not be shown if the autofill service does not support it, if the autofill
+ * request has not returned a response yet, if the dialog was shown previously, or if the
+ * input method is already shown.
* <p>
* It is recommended apps to call this method the first time a user focuses on
* an autofill-able form, and to avoid showing the input method if the dialog is shown. If
@@ -3068,9 +3088,16 @@ public final class AutofillManager {
// TODO(b/210926084): Consider whether to include the one-time show logic within this method.
public boolean showAutofillDialog(@NonNull View view) {
Objects.requireNonNull(view);
- if (shouldShowAutofillDialog(view.getAutofillId())) {
- // If the id matches a trigger id, this will trigger the fill dialog.
- notifyViewEntered(view);
+ if (shouldShowAutofillDialog(view, view.getAutofillId())) {
+ mShowAutofillDialogCalled = true;
+ final WeakReference<View> wrView = new WeakReference<>(view);
+ // The id matches a trigger id, this will trigger the fill dialog.
+ post(() -> {
+ final View v = wrView.get();
+ if (v != null) {
+ notifyViewEntered(v);
+ }
+ });
return true;
}
return false;
@@ -3099,18 +3126,33 @@ public final class AutofillManager {
*/
public boolean showAutofillDialog(@NonNull View view, int virtualId) {
Objects.requireNonNull(view);
- if (shouldShowAutofillDialog(getAutofillId(view, virtualId))) {
- // If the id matches a trigger id, this will trigger the fill dialog.
- notifyViewEntered(view, virtualId, /* bounds= */ null, /* flags= */ 0);
+ if (shouldShowAutofillDialog(view, getAutofillId(view, virtualId))) {
+ mShowAutofillDialogCalled = true;
+ final WeakReference<View> wrView = new WeakReference<>(view);
+ // The id matches a trigger id, this will trigger the fill dialog.
+ post(() -> {
+ final View v = wrView.get();
+ if (v != null) {
+ notifyViewEntered(v, virtualId, /* bounds= */ null, /* flags= */ 0);
+ }
+ });
return true;
}
return false;
}
- private boolean shouldShowAutofillDialog(AutofillId id) {
- if (!hasFillDialogUiFeature() || mFillDialogTriggerIds == null) {
+ private boolean shouldShowAutofillDialog(View view, AutofillId id) {
+ if (!hasFillDialogUiFeature()
+ || mShowAutofillDialogCalled
+ || mFillDialogTriggerIds == null) {
return false;
}
+
+ if (getImeStateFlag(view) == FLAG_IME_SHOWING) {
+ // IME is showing
+ return false;
+ }
+
final int size = mFillDialogTriggerIds.size();
for (int i = 0; i < size; i++) {
AutofillId fillId = mFillDialogTriggerIds.get(i);
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
index 7f07146776ab..a17089169b61 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfo.java
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -415,7 +415,7 @@ public final class CursorAnchorInfo implements Parcelable {
"required when positional parameters are specified.");
}
}
- return new CursorAnchorInfo(this);
+ return CursorAnchorInfo.create(this);
}
/**
@@ -440,31 +440,93 @@ public final class CursorAnchorInfo implements Parcelable {
}
}
- private CursorAnchorInfo(final Builder builder) {
- mSelectionStart = builder.mSelectionStart;
- mSelectionEnd = builder.mSelectionEnd;
- mComposingTextStart = builder.mComposingTextStart;
- mComposingText = builder.mComposingText;
- mInsertionMarkerFlags = builder.mInsertionMarkerFlags;
- mInsertionMarkerHorizontal = builder.mInsertionMarkerHorizontal;
- mInsertionMarkerTop = builder.mInsertionMarkerTop;
- mInsertionMarkerBaseline = builder.mInsertionMarkerBaseline;
- mInsertionMarkerBottom = builder.mInsertionMarkerBottom;
- mCharacterBoundsArray = builder.mCharacterBoundsArrayBuilder != null
- ? builder.mCharacterBoundsArrayBuilder.build() : null;
- mEditorBoundsInfo = builder.mEditorBoundsInfo;
- mMatrixValues = new float[9];
+ private static CursorAnchorInfo create(Builder builder) {
+ final SparseRectFArray characterBoundsArray =
+ builder.mCharacterBoundsArrayBuilder != null
+ ? builder.mCharacterBoundsArrayBuilder.build()
+ : null;
+ final float[] matrixValues = new float[9];
if (builder.mMatrixInitialized) {
- System.arraycopy(builder.mMatrixValues, 0, mMatrixValues, 0, 9);
+ System.arraycopy(builder.mMatrixValues, 0, matrixValues, 0, 9);
} else {
- Matrix.IDENTITY_MATRIX.getValues(mMatrixValues);
+ Matrix.IDENTITY_MATRIX.getValues(matrixValues);
}
+ return new CursorAnchorInfo(builder.mSelectionStart, builder.mSelectionEnd,
+ builder.mComposingTextStart, builder.mComposingText, builder.mInsertionMarkerFlags,
+ builder.mInsertionMarkerHorizontal, builder.mInsertionMarkerTop,
+ builder.mInsertionMarkerBaseline, builder.mInsertionMarkerBottom,
+ characterBoundsArray, builder.mEditorBoundsInfo, matrixValues);
+ }
+
+ private CursorAnchorInfo(int selectionStart, int selectionEnd, int composingTextStart,
+ @Nullable CharSequence composingText, int insertionMarkerFlags,
+ float insertionMarkerHorizontal, float insertionMarkerTop,
+ float insertionMarkerBaseline, float insertionMarkerBottom,
+ @Nullable SparseRectFArray characterBoundsArray,
+ @Nullable EditorBoundsInfo editorBoundsInfo,
+ @NonNull float[] matrixValues) {
+ mSelectionStart = selectionStart;
+ mSelectionEnd = selectionEnd;
+ mComposingTextStart = composingTextStart;
+ mComposingText = composingText;
+ mInsertionMarkerFlags = insertionMarkerFlags;
+ mInsertionMarkerHorizontal = insertionMarkerHorizontal;
+ mInsertionMarkerTop = insertionMarkerTop;
+ mInsertionMarkerBaseline = insertionMarkerBaseline;
+ mInsertionMarkerBottom = insertionMarkerBottom;
+ mCharacterBoundsArray = characterBoundsArray;
+ mEditorBoundsInfo = editorBoundsInfo;
+ mMatrixValues = matrixValues;
+
// To keep hash function simple, we only use some complex objects for hash.
- int hash = Objects.hashCode(mComposingText);
- hash *= 31;
- hash += Arrays.hashCode(mMatrixValues);
- mHashCode = hash;
+ int hashCode = Objects.hashCode(mComposingText);
+ hashCode *= 31;
+ hashCode += Arrays.hashCode(mMatrixValues);
+ mHashCode = hashCode;
+ }
+
+ /**
+ * Creates a new instance of {@link CursorAnchorInfo} by applying {@code parentMatrix} to
+ * the coordinate transformation matrix.
+ *
+ * @param original {@link CursorAnchorInfo} to be cloned from.
+ * @param parentMatrix {@link Matrix} to be applied to {@code original.getMatrix()}
+ * @return A new instance of {@link CursorAnchorInfo} whose {@link CursorAnchorInfo#getMatrix()}
+ * returns {@code parentMatrix * original.getMatrix()}.
+ * @hide
+ */
+ public static CursorAnchorInfo createForAdditionalParentMatrix(CursorAnchorInfo original,
+ @NonNull Matrix parentMatrix) {
+ return new CursorAnchorInfo(original.mSelectionStart, original.mSelectionEnd,
+ original.mComposingTextStart, original.mComposingText,
+ original.mInsertionMarkerFlags, original.mInsertionMarkerHorizontal,
+ original.mInsertionMarkerTop, original.mInsertionMarkerBaseline,
+ original.mInsertionMarkerBottom, original.mCharacterBoundsArray,
+ original.mEditorBoundsInfo, computeMatrixValues(parentMatrix, original));
+ }
+
+ /**
+ * Returns a float array that represents {@link Matrix} elements for
+ * {@code parentMatrix * info.getMatrix()}.
+ *
+ * @param parentMatrix {@link Matrix} to be multiplied.
+ * @param info {@link CursorAnchorInfo} to provide {@link Matrix} to be multiplied.
+ * @return {@code parentMatrix * info.getMatrix()}.
+ */
+ private static float[] computeMatrixValues(@NonNull Matrix parentMatrix,
+ @NonNull CursorAnchorInfo info) {
+ if (parentMatrix.isIdentity()) {
+ return info.mMatrixValues;
+ }
+
+ final Matrix newMatrix = new Matrix();
+ newMatrix.setValues(info.mMatrixValues);
+ newMatrix.postConcat(parentMatrix);
+
+ final float[] matrixValues = new float[9];
+ newMatrix.getValues(matrixValues);
+ return matrixValues;
}
/**
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index da20e336627c..805f8e7551a5 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -53,6 +53,7 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.graphics.Matrix;
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
import android.os.Binder;
@@ -453,6 +454,18 @@ public final class InputMethodManager {
private CursorAnchorInfo mCursorAnchorInfo = null;
/**
+ * A special {@link Matrix} that can be provided by the system when this instance is running
+ * inside a virtual display.
+ *
+ * <p>If this is non-{@code null}, {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}
+ * should be adjusted with this {@link Matrix}.</p>
+ *
+ * <p>{@code null} when not used.</p>
+ */
+ @GuardedBy("mH")
+ private Matrix mVirtualDisplayToScreenMatrix = null;
+
+ /**
* As reported by {@link InputBindResult}. This value is determined by
* {@link com.android.internal.R.styleable#InputMethod_suppressesSpellChecking}.
*/
@@ -528,6 +541,7 @@ public final class InputMethodManager {
static final int MSG_REPORT_FULLSCREEN_MODE = 10;
static final int MSG_BIND_ACCESSIBILITY_SERVICE = 11;
static final int MSG_UNBIND_ACCESSIBILITY_SERVICE = 12;
+ static final int MSG_UPDATE_VIRTUAL_DISPLAY_TO_SCREEN_MATRIX = 30;
private static boolean isAutofillUIShowing(View servedView) {
AutofillManager afm = servedView.getContext().getSystemService(AutofillManager.class);
@@ -892,6 +906,7 @@ public final class InputMethodManager {
InputMethodSessionWrapper.createOrNull(res.method);
mCurId = res.id;
mBindSequence = res.sequence;
+ mVirtualDisplayToScreenMatrix = res.getVirtualDisplayToScreenMatrix();
mIsInputMethodSuppressingSpellChecker =
res.isInputMethodSuppressingSpellChecker;
}
@@ -1063,6 +1078,45 @@ public final class InputMethodManager {
}
return;
}
+ case MSG_UPDATE_VIRTUAL_DISPLAY_TO_SCREEN_MATRIX: {
+ final float[] matrixValues = (float[]) msg.obj;
+ final int bindSequence = msg.arg1;
+ synchronized (mH) {
+ if (mBindSequence != bindSequence) {
+ return;
+ }
+ if (matrixValues == null || mVirtualDisplayToScreenMatrix == null) {
+ // Either InputBoundResult#mVirtualDisplayToScreenMatrixValues is null
+ // OR this app is unbound from the parent VirtualDisplay. In this case,
+ // calling updateCursorAnchorInfo() isn't safe. Only clear the matrix.
+ mVirtualDisplayToScreenMatrix = null;
+ return;
+ }
+
+ final float[] currentValues = new float[9];
+ mVirtualDisplayToScreenMatrix.getValues(currentValues);
+ if (Arrays.equals(currentValues, matrixValues)) {
+ return;
+ }
+ mVirtualDisplayToScreenMatrix.setValues(matrixValues);
+
+ if (mCursorAnchorInfo == null || mCurrentInputMethodSession == null
+ || mServedInputConnection == null) {
+ return;
+ }
+ final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode
+ & InputConnection.CURSOR_UPDATE_MONITOR) != 0;
+ if (!isMonitoring) {
+ return;
+ }
+ // Since the host VirtualDisplay is moved, we need to issue
+ // IMS#updateCursorAnchorInfo() again.
+ mCurrentInputMethodSession.updateCursorAnchorInfo(
+ CursorAnchorInfo.createForAdditionalParentMatrix(
+ mCursorAnchorInfo, mVirtualDisplayToScreenMatrix));
+ }
+ return;
+ }
}
}
}
@@ -1128,6 +1182,12 @@ public final class InputMethodManager {
}
@Override
+ public void updateVirtualDisplayToScreenMatrix(int bindSequence, float[] matrixValues) {
+ mH.obtainMessage(MSG_UPDATE_VIRTUAL_DISPLAY_TO_SCREEN_MATRIX, bindSequence, 0,
+ matrixValues).sendToTarget();
+ }
+
+ @Override
public void setImeTraceEnabled(boolean enabled) {
ImeTracing.getInstance().setEnabled(enabled);
}
@@ -1596,7 +1656,9 @@ public final class InputMethodManager {
* Disconnect any existing input connection, clearing the served view.
*/
@UnsupportedAppUsage
+ @GuardedBy("mH")
void finishInputLocked() {
+ mVirtualDisplayToScreenMatrix = null;
mIsInputMethodSuppressingSpellChecker = false;
setNextServedViewLocked(null);
if (getServedViewLocked() != null) {
@@ -2275,6 +2337,7 @@ public final class InputMethodManager {
+ InputMethodDebug.startInputFlagsToString(startInputFlags));
return false;
}
+ mVirtualDisplayToScreenMatrix = res.getVirtualDisplayToScreenMatrix();
mIsInputMethodSuppressingSpellChecker = res.isInputMethodSuppressingSpellChecker;
if (res.id != null) {
setInputChannelLocked(res.channel);
@@ -2695,7 +2758,13 @@ public final class InputMethodManager {
return;
}
if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo);
- mCurrentInputMethodSession.updateCursorAnchorInfo(cursorAnchorInfo);
+ if (mVirtualDisplayToScreenMatrix != null) {
+ mCurrentInputMethodSession.updateCursorAnchorInfo(
+ CursorAnchorInfo.createForAdditionalParentMatrix(
+ cursorAnchorInfo, mVirtualDisplayToScreenMatrix));
+ } else {
+ mCurrentInputMethodSession.updateCursorAnchorInfo(cursorAnchorInfo);
+ }
mCursorAnchorInfo = cursorAnchorInfo;
// Clear immediate bit (if any).
mRequestUpdateCursorAnchorInfoMonitorMode &= ~CURSOR_UPDATE_IMMEDIATE;
@@ -3269,6 +3338,43 @@ public final class InputMethodManager {
}
/**
+ * An internal API for {@link android.hardware.display.VirtualDisplay} to report where its
+ * embedded virtual display is placed.
+ *
+ * @param childDisplayId Display ID of the embedded virtual display.
+ * @param matrix {@link Matrix} to convert virtual display screen coordinates to
+ * the host screen coordinates. {@code null} to clear the relationship.
+ * @hide
+ */
+ public void reportVirtualDisplayGeometry(int childDisplayId, @Nullable Matrix matrix) {
+ try {
+ final float[] matrixValues;
+ if (matrix == null) {
+ matrixValues = null;
+ } else {
+ matrixValues = new float[9];
+ matrix.getValues(matrixValues);
+ }
+ mService.reportVirtualDisplayGeometryAsync(mClient, childDisplayId, matrixValues);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * An internal API that returns if the current display has a transformation matrix to apply.
+ *
+ * @return {@code true} if {@link Matrix} to convert virtual display screen coordinates to
+ * the host screen coordinates is set.
+ * @hide
+ */
+ public boolean hasVirtualDisplayToScreenMatrix() {
+ synchronized (mH) {
+ return mVirtualDisplayToScreenMatrix != null;
+ }
+ }
+
+ /**
* Force switch to the last used input method and subtype. If the last input method didn't have
* any subtypes, the framework will simply switch to the last input method with no subtype
* specified.
diff --git a/core/java/android/view/translation/UiTranslationManager.java b/core/java/android/view/translation/UiTranslationManager.java
index 01acdfec6c27..9fc7b07200ae 100644
--- a/core/java/android/view/translation/UiTranslationManager.java
+++ b/core/java/android/view/translation/UiTranslationManager.java
@@ -163,7 +163,6 @@ public final class UiTranslationManager {
/**
* @removed Use {@link #startTranslation(TranslationSpec, TranslationSpec, List, ActivityId,
* UiTranslationSpec)} instead.
- *
* @hide
*/
@RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
@@ -180,13 +179,13 @@ public final class UiTranslationManager {
/**
* Request ui translation for a given Views.
*
- * @param sourceSpec {@link TranslationSpec} for the data to be translated.
- * @param targetSpec {@link TranslationSpec} for the translated data.
- * @param viewIds A list of the {@link View}'s {@link AutofillId} which needs to be translated
- * @param activityId the identifier for the Activity which needs ui translation
+ * @param sourceSpec {@link TranslationSpec} for the data to be translated.
+ * @param targetSpec {@link TranslationSpec} for the translated data.
+ * @param viewIds A list of the {@link View}'s {@link AutofillId} which needs to be
+ * translated
+ * @param activityId the identifier for the Activity which needs ui translation
* @param uiTranslationSpec configuration for translation of the specified views
* @throws IllegalArgumentException if the no {@link View}'s {@link AutofillId} in the list
- *
* @hide
*/
@RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
@@ -220,8 +219,7 @@ public final class UiTranslationManager {
*
* @param activityId the identifier for the Activity which needs ui translation
* @throws NullPointerException the activityId or
- * {@link android.app.assist.ActivityId#getToken()} is {@code null}
- *
+ * {@link android.app.assist.ActivityId#getToken()} is {@code null}
* @hide
*/
@RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
@@ -245,8 +243,7 @@ public final class UiTranslationManager {
*
* @param activityId the identifier for the Activity which needs ui translation
* @throws NullPointerException the activityId or
- * {@link android.app.assist.ActivityId#getToken()} is {@code null}
- *
+ * {@link android.app.assist.ActivityId#getToken()} is {@code null}
* @hide
*/
@RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
@@ -270,8 +267,7 @@ public final class UiTranslationManager {
*
* @param activityId the identifier for the Activity which needs ui translation
* @throws NullPointerException the activityId or
- * {@link android.app.assist.ActivityId#getToken()} is {@code null}
- *
+ * {@link android.app.assist.ActivityId#getToken()} is {@code null}
* @hide
*/
@RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
@@ -290,20 +286,29 @@ public final class UiTranslationManager {
}
/**
- * Register for notifications of UI Translation state changes on the foreground activity. This
+ * Register for notifications of UI Translation state changes on the foreground Activity. This
* is available to the owning application itself and also the current input method.
* <p>
* The application whose UI is being translated can use this to customize the UI Translation
* behavior in ways that aren't made easy by methods like
* {@link View#onCreateViewTranslationRequest(int[], Consumer)}.
- *
* <p>
* Input methods can use this to offer complementary features to UI Translation; for example,
* enabling outgoing message translation when the system is translating incoming messages in a
* communication app.
+ * <p>
+ * Starting from {@link android.os.Build.VERSION_CODES#TIRAMISU}, if Activities are already
+ * being translated when a callback is registered, methods on the callback will be invoked for
+ * each translated activity, depending on the state of translation:
+ * <ul>
+ * <li>If translation is <em>not</em> paused,
+ * {@link UiTranslationStateCallback#onStarted} will be invoked.</li>
+ * <li>If translation <em>is</em> paused, {@link UiTranslationStateCallback#onStarted}
+ * will first be invoked, followed by {@link UiTranslationStateCallback#onPaused}.</li>
+ * </ul>
*
* @param callback the callback to register for receiving the state change
- * notifications
+ * notifications
*/
public void registerUiTranslationStateCallback(
@NonNull @CallbackExecutor Executor executor,
@@ -355,9 +360,8 @@ public final class UiTranslationManager {
* called or Activity is destroyed.
*
* @param activityDestroyed if the ui translation is finished because of activity destroyed.
- * @param activityId the identifier for the Activity which needs ui translation
- * @param componentName the ui translated Activity componentName.
- *
+ * @param activityId the identifier for the Activity which needs ui translation
+ * @param componentName the ui translated Activity componentName.
* @hide
*/
public void onTranslationFinished(boolean activityDestroyed, ActivityId activityId,
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6f83a45ce7c6..f9c964158e2e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -11458,7 +11458,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Show the IME, except when selecting in read-only text.
final InputMethodManager imm = getInputMethodManager();
viewClicked(imm);
- if (isTextEditable() && mEditor.mShowSoftInputOnFocus && imm != null) {
+ if (isTextEditable() && mEditor.mShowSoftInputOnFocus && imm != null
+ && !showAutofillDialog()) {
imm.showSoftInput(this, 0);
}
@@ -11476,6 +11477,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return superResult;
}
+ /**
+ * The fill dialog UI is a more conspicuous and efficient interface than dropdown UI.
+ * If autofill suggestions are available when the user clicks on a field that supports filling
+ * the dialog UI, Autofill will pop up a fill dialog. The dialog will take up a larger area
+ * to display the datasets, so it is easy for users to pay attention to the datasets and
+ * selecting a dataset. The autofill dialog is shown as the bottom sheet, the better
+ * experience is not to show the IME if there is a fill dialog.
+ */
+ private boolean showAutofillDialog() {
+ final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
+ if (afm != null) {
+ return afm.showAutofillDialog(this);
+ }
+ return false;
+ }
+
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (mMovement != null && mText instanceof Spannable && mLayout != null) {
diff --git a/core/java/android/window/OnBackInvokedDispatcher.java b/core/java/android/window/OnBackInvokedDispatcher.java
index 5eed8cde8c7c..c254a9df3b4c 100644
--- a/core/java/android/window/OnBackInvokedDispatcher.java
+++ b/core/java/android/window/OnBackInvokedDispatcher.java
@@ -21,9 +21,6 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
-import android.annotation.TestApi;
-import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledSince;
import android.os.Build;
import java.lang.annotation.Retention;
@@ -38,23 +35,6 @@ import java.lang.annotation.RetentionPolicy;
* target (a.k.a. the callback to be invoked next), or its behavior.
*/
public interface OnBackInvokedDispatcher {
- /**
- * Enables dispatching the "back" action via {@link OnBackInvokedDispatcher}.
- *
- * When enabled, the following APIs are no longer invoked:
- * <ul>
- * <li> {@link android.app.Activity#onBackPressed}
- * <li> {@link android.app.Dialog#onBackPressed}
- * <li> {@link android.view.KeyEvent#KEYCODE_BACK} is no longer dispatched.
- * </ul>
- *
- * @hide
- */
- @TestApi
- @ChangeId
- @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
- long DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME = 195946584L;
-
/** @hide */
String TAG = "OnBackInvokedDispatcher";
diff --git a/core/java/android/window/PictureInPictureSurfaceTransaction.java b/core/java/android/window/PictureInPictureSurfaceTransaction.java
index 2bf2f3193789..0a751c38cfff 100644
--- a/core/java/android/window/PictureInPictureSurfaceTransaction.java
+++ b/core/java/android/window/PictureInPictureSurfaceTransaction.java
@@ -47,6 +47,8 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
public final float mCornerRadius;
+ public final float mShadowRadius;
+
private final Rect mWindowCrop;
private PictureInPictureSurfaceTransaction(Parcel in) {
@@ -56,11 +58,12 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
in.readFloatArray(mFloat9);
mRotation = in.readFloat();
mCornerRadius = in.readFloat();
+ mShadowRadius = in.readFloat();
mWindowCrop = in.readTypedObject(Rect.CREATOR);
}
private PictureInPictureSurfaceTransaction(float alpha, @Nullable PointF position,
- @Nullable float[] float9, float rotation, float cornerRadius,
+ @Nullable float[] float9, float rotation, float cornerRadius, float shadowRadius,
@Nullable Rect windowCrop) {
mAlpha = alpha;
mPosition = position;
@@ -73,12 +76,14 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
mRotation = rotation;
}
mCornerRadius = cornerRadius;
+ mShadowRadius = shadowRadius;
mWindowCrop = (windowCrop == null) ? null : new Rect(windowCrop);
}
public PictureInPictureSurfaceTransaction(PictureInPictureSurfaceTransaction other) {
this(other.mAlpha, other.mPosition,
- other.mFloat9, other.mRotation, other.mCornerRadius, other.mWindowCrop);
+ other.mFloat9, other.mRotation, other.mCornerRadius, other.mShadowRadius,
+ other.mWindowCrop);
}
/** @return {@link Matrix} from {@link #mFloat9} */
@@ -93,6 +98,11 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
return mCornerRadius > 0;
}
+ /** @return {@code true} if this transaction contains setting shadow radius. */
+ public boolean hasShadowRadiusSet() {
+ return mShadowRadius > 0;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -103,13 +113,14 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
&& Arrays.equals(mFloat9, that.mFloat9)
&& Objects.equals(mRotation, that.mRotation)
&& Objects.equals(mCornerRadius, that.mCornerRadius)
+ && Objects.equals(mShadowRadius, that.mShadowRadius)
&& Objects.equals(mWindowCrop, that.mWindowCrop);
}
@Override
public int hashCode() {
return Objects.hash(mAlpha, mPosition, Arrays.hashCode(mFloat9),
- mRotation, mCornerRadius, mWindowCrop);
+ mRotation, mCornerRadius, mShadowRadius, mWindowCrop);
}
@Override
@@ -124,6 +135,7 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
out.writeFloatArray(mFloat9);
out.writeFloat(mRotation);
out.writeFloat(mCornerRadius);
+ out.writeFloat(mShadowRadius);
out.writeTypedObject(mWindowCrop, 0 /* flags */);
}
@@ -136,6 +148,7 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
+ " matrix=" + matrix.toShortString()
+ " rotation=" + mRotation
+ " cornerRadius=" + mCornerRadius
+ + " shadowRadius=" + mShadowRadius
+ " crop=" + mWindowCrop
+ ")";
}
@@ -156,6 +169,9 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
if (surfaceTransaction.hasCornerRadiusSet()) {
tx.setCornerRadius(surfaceControl, surfaceTransaction.mCornerRadius);
}
+ if (surfaceTransaction.hasShadowRadiusSet()) {
+ tx.setShadowRadius(surfaceControl, surfaceTransaction.mShadowRadius);
+ }
if (surfaceTransaction.mAlpha != NOT_SET) {
tx.setAlpha(surfaceControl, surfaceTransaction.mAlpha);
}
@@ -178,6 +194,7 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
private float[] mFloat9;
private float mRotation;
private float mCornerRadius = NOT_SET;
+ private float mShadowRadius = NOT_SET;
private Rect mWindowCrop;
public Builder setAlpha(float alpha) {
@@ -201,6 +218,11 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
return this;
}
+ public Builder setShadowRadius(float shadowRadius) {
+ mShadowRadius = shadowRadius;
+ return this;
+ }
+
public Builder setWindowCrop(@NonNull Rect windowCrop) {
mWindowCrop = new Rect(windowCrop);
return this;
@@ -208,7 +230,7 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
public PictureInPictureSurfaceTransaction build() {
return new PictureInPictureSurfaceTransaction(mAlpha, mPosition,
- mFloat9, mRotation, mCornerRadius, mWindowCrop);
+ mFloat9, mRotation, mCornerRadius, mShadowRadius, mWindowCrop);
}
}
}
diff --git a/core/java/android/window/SurfaceSyncer.java b/core/java/android/window/SurfaceSyncer.java
index 0c32219f79a0..0e011bb0d0b3 100644
--- a/core/java/android/window/SurfaceSyncer.java
+++ b/core/java/android/window/SurfaceSyncer.java
@@ -21,15 +21,16 @@ import android.annotation.Nullable;
import android.annotation.UiThread;
import android.os.Handler;
import android.os.Looper;
+import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceView;
import android.view.View;
+import android.view.ViewRootImpl;
import com.android.internal.annotations.GuardedBy;
-import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -99,7 +100,9 @@ public class SurfaceSyncer {
Handler handler = new Handler(Looper.myLooper());
return setupSync(transaction -> {
transaction.apply();
- handler.post(onComplete);
+ if (onComplete != null) {
+ handler.post(onComplete);
+ }
});
}
@@ -171,7 +174,11 @@ public class SurfaceSyncer {
*/
@UiThread
public boolean addToSync(int syncId, @NonNull View view) {
- return addToSync(syncId, view.getViewRootImpl().mSyncTarget);
+ ViewRootImpl viewRoot = view.getViewRootImpl();
+ if (viewRoot == null) {
+ return false;
+ }
+ return addToSync(syncId, viewRoot.mSyncTarget);
}
/**
@@ -232,9 +239,17 @@ public class SurfaceSyncer {
* and {@link SyncBufferCallback#onBufferReady(Transaction)} in order for this Syncable
* to be marked as complete.
*
+ * Always invoked on the thread that initiated the call to
+ * {@link #addToSync(int, SyncTarget)}
+ *
* @param syncBufferCallback A SyncBufferCallback that the caller must invoke onBufferReady
*/
void onReadyToSync(SyncBufferCallback syncBufferCallback);
+
+ /**
+ * There's no guarantee about the thread this callback is invoked on.
+ */
+ default void onSyncComplete() {}
}
/**
@@ -260,11 +275,13 @@ public class SurfaceSyncer {
private final Object mLock = new Object();
@GuardedBy("mLock")
- private final Set<Integer> mPendingSyncs = new HashSet<>();
+ private final Set<Integer> mPendingSyncs = new ArraySet<>();
@GuardedBy("mLock")
private final Transaction mTransaction = sTransactionFactory.get();
@GuardedBy("mLock")
private boolean mSyncReady;
+ @GuardedBy("mLock")
+ private final Set<SyncTarget> mSyncTargets = new ArraySet<>();
private final int mSyncId;
private final Consumer<Transaction> mSyncRequestCompleteCallback;
@@ -290,6 +307,7 @@ public class SurfaceSyncer {
synchronized (mLock) {
mPendingSyncs.add(syncBufferCallback.hashCode());
+ mSyncTargets.add(syncTarget);
}
syncTarget.onReadyToSync(syncBufferCallback);
}
@@ -314,6 +332,11 @@ public class SurfaceSyncer {
if (DEBUG) {
Log.d(TAG, "Successfully finished sync id=" + mSyncId);
}
+
+ for (SyncTarget syncTarget : mSyncTargets) {
+ syncTarget.onSyncComplete();
+ }
+ mSyncTargets.clear();
mSyncRequestCompleteCallback.accept(mTransaction);
}
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index e0bee96002b8..8811116b25ad 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -18,7 +18,6 @@ package android.window;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.compat.CompatChanges;
import android.content.Context;
import android.os.Debug;
import android.os.Handler;
@@ -253,21 +252,20 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
* {@link OnBackInvokedCallback}.
*/
public static boolean isOnBackInvokedCallbackEnabled(@Nullable Context context) {
- // new back is enabled if the app targets T AND the feature flag is enabled AND the app
- // does not explicitly request legacy back.
- boolean targetsT = CompatChanges.isChangeEnabled(DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME);
+ // new back is enabled if the feature flag is enabled AND the app does not explicitly
+ // request legacy back.
boolean featureFlagEnabled = IS_BACK_PREDICTABILITY_ENABLED;
// If the context is null, we assume true and fallback on the two other conditions.
- boolean appRequestsLegacy =
- context == null || !context.getApplicationInfo().isOnBackInvokedCallbackEnabled();
+ boolean appRequestsPredictiveBack =
+ context != null && context.getApplicationInfo().isOnBackInvokedCallbackEnabled();
if (DEBUG) {
- Log.d(TAG, TextUtils.formatSimple("App: %s isChangeEnabled=%s featureFlagEnabled=%s "
- + "onBackInvokedEnabled=%s",
+ Log.d(TAG, TextUtils.formatSimple("App: %s featureFlagEnabled=%s "
+ + "appRequestsPredictiveBack=%s",
context != null ? context.getApplicationInfo().packageName : "null context",
- targetsT, featureFlagEnabled, !appRequestsLegacy));
+ featureFlagEnabled, appRequestsPredictiveBack));
}
- return targetsT && featureFlagEnabled && !appRequestsLegacy;
+ return featureFlagEnabled && appRequestsPredictiveBack;
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 96728ed89b70..88089b5b85f2 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -152,18 +152,6 @@ public class ChooserActivity extends ResolverActivity implements
SelectableTargetInfoCommunicator {
private static final String TAG = "ChooserActivity";
- /**
- * Whether this chooser is operating in "headless springboard" mode (as determined during
- * onCreate). In this mode, our activity sits in the background and waits for the new
- * "unbundled" chooser to handle the Sharesheet experience; the system ChooserActivity is
- * responsible only for providing the startActivityAsCaller permission token and keeping it
- * valid for the life of the unbundled delegate activity.
- *
- * TODO: when the unbundled chooser is fully launched, the system-side "springboard" can use a
- * simpler implementation that doesn't inherit from ResolverActivity.
- */
- private boolean mIsHeadlessSpringboardActivity;
-
private AppPredictor mPersonalAppPredictor;
private AppPredictor mWorkAppPredictor;
private boolean mShouldDisplayLandscape;
@@ -259,11 +247,6 @@ public class ChooserActivity extends ResolverActivity implements
private static final float DIRECT_SHARE_EXPANSION_RATE = 0.78f;
- private boolean mEnableChooserDelegate =
- DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.USE_DELEGATE_CHOOSER,
- false);
-
private static final int DEFAULT_SALT_EXPIRATION_DAYS = 7;
private int mMaxHashSaltDays = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.HASH_SALT_MAX_DAYS,
@@ -530,12 +513,6 @@ public class ChooserActivity extends ResolverActivity implements
@Override
protected void onCreate(Bundle savedInstanceState) {
- if (handOverToDelegateChooser()) {
- super_onCreate(savedInstanceState);
- mIsHeadlessSpringboardActivity = true;
- return;
- }
-
final long intentReceivedTime = System.currentTimeMillis();
getChooserActivityLogger().logSharesheetTriggered();
// This is the only place this value is being set. Effectively final.
@@ -751,56 +728,6 @@ public class ChooserActivity extends ResolverActivity implements
postponeEnterTransition();
}
- private boolean handOverToDelegateChooser() {
- // Check the explicit classname so that we don't interfere with the flow of any subclasses.
- if (!this.getClass().getName().equals("com.android.internal.app.ChooserActivity")
- || !mEnableChooserDelegate) {
- return false;
- }
-
- Intent delegationIntent = new Intent();
- final ComponentName delegateActivity = ComponentName.unflattenFromString(
- Resources.getSystem().getString(R.string.config_chooserActivity));
- delegationIntent.setComponent(delegateActivity);
- delegationIntent.putExtra(Intent.EXTRA_INTENT, getIntent());
- delegationIntent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
-
- // Don't close until the delegate finishes, or the token will be invalidated.
- mAwaitingDelegateResponse = true;
- startActivityForResult(delegationIntent, REQUEST_CODE_RETURN_FROM_DELEGATE_CHOOSER);
- return true;
- }
-
- @Override
- protected void onRestart() {
- if (mIsHeadlessSpringboardActivity) {
- super_onRestart();
- return;
- }
-
- super.onRestart();
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- if (mIsHeadlessSpringboardActivity) {
- super_onSaveInstanceState(outState);
- return;
- }
-
- super.onSaveInstanceState(outState);
- }
-
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState) {
- if (mIsHeadlessSpringboardActivity) {
- super_onRestoreInstanceState(savedInstanceState);
- return;
- }
-
- super.onRestoreInstanceState(savedInstanceState);
- }
-
@Override
protected int appliedThemeResId() {
return R.style.Theme_DeviceDefault_Chooser;
@@ -1059,11 +986,6 @@ public class ChooserActivity extends ResolverActivity implements
@Override
public void onConfigurationChanged(Configuration newConfig) {
- if (mIsHeadlessSpringboardActivity) {
- super_onConfigurationChanged(newConfig);
- return;
- }
-
super.onConfigurationChanged(newConfig);
ViewPager viewPager = findViewById(R.id.profile_pager);
if (viewPager.isLayoutRtl()) {
@@ -1236,9 +1158,7 @@ public class ChooserActivity extends ResolverActivity implements
-1);
// Action bar is user-independent, always start as primary
safelyStartActivityAsUser(ti, getPersonalProfileUserHandle());
- if (!mAwaitingDelegateResponse) {
- finish();
- }
+ finish();
}
);
b.setId(R.id.chooser_nearby_button);
@@ -1260,9 +1180,7 @@ public class ChooserActivity extends ResolverActivity implements
-1);
// Action bar is user-independent, always start as primary
safelyStartActivityAsUser(ti, getPersonalProfileUserHandle());
- if (!mAwaitingDelegateResponse) {
- finish();
- }
+ finish();
}
);
b.setId(R.id.chooser_edit_button);
@@ -1616,10 +1534,6 @@ public class ChooserActivity extends ResolverActivity implements
protected void onDestroy() {
super.onDestroy();
- if (mIsHeadlessSpringboardActivity) {
- return;
- }
-
if (mRefinementResultReceiver != null) {
mRefinementResultReceiver.destroy();
mRefinementResultReceiver = null;
@@ -2313,9 +2227,7 @@ public class ChooserActivity extends ResolverActivity implements
TargetInfo clonedTarget = selectedTarget.cloneFilledIn(matchingIntent, 0);
if (super.onTargetSelected(clonedTarget, false)) {
updateModelAndChooserCounts(clonedTarget);
- if (!mAwaitingDelegateResponse) {
- finish();
- }
+ finish();
return;
}
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index dc68e16e2eb6..ea8589bddabb 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -210,7 +210,7 @@ public class ResolverActivity extends Activity implements
private UserHandle mWorkProfileUserHandle;
- protected boolean mAwaitingDelegateResponse;
+
/**
* Get the string resource to be used as a label for the link to the resolver activity for an
@@ -328,86 +328,6 @@ public class ResolverActivity extends Activity implements
super.onCreate(savedInstanceState);
}
- /**
- * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode
- * where we hand over to the unbundled chooser (while violating many of the invariants of a
- * typical ResolverActivity implementation). Subclasses running in this mode need to be able
- * to opt-out of the normal ResolverActivity behavior.
- *
- * TODO: this should be removed later on in the unbundling migration, when the springboard
- * activity no longer needs to derive from ResolverActivity. The hold-over design here is
- * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as
- * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity
- * implementations that depend on the invariants that are violated in the headless mode). If
- * necessary, we could instead consider using a springboard-only activity on the system side
- * immediately, which would delegate either to the unbundled chooser, or to a
- * (properly-inheriting) system ChooserActivity. This would have performance implications even
- * when the unbundling experiment is disabled.
- */
- protected void super_onRestart() {
- super.onRestart();
- }
-
- /**
- * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode
- * where we hand over to the unbundled chooser (while violating many of the invariants of a
- * typical ResolverActivity implementation). Subclasses running in this mode need to be able
- * to opt-out of the normal ResolverActivity behavior.
- *
- * TODO: this should be removed later on in the unbundling migration, when the springboard
- * activity no longer needs to derive from ResolverActivity. The hold-over design here is
- * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as
- * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity
- * implementations that depend on the invariants that are violated in the headless mode). If
- * necessary, we could instead consider using a springboard-only activity on the system side
- * immediately, which would delegate either to the unbundled chooser, or to a
- * (properly-inheriting) system ChooserActivity. This would have performance implications even
- * when the unbundling experiment is disabled.
- */
- protected void super_onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- }
-
- /**
- * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode
- * where we hand over to the unbundled chooser (while violating many of the invariants of a
- * typical ResolverActivity implementation). Subclasses running in this mode need to be able
- * to opt-out of the normal ResolverActivity behavior.
- *
- * TODO: this should be removed later on in the unbundling migration, when the springboard
- * activity no longer needs to derive from ResolverActivity. The hold-over design here is
- * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as
- * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity
- * implementations that depend on the invariants that are violated in the headless mode). If
- * necessary, we could instead consider using a springboard-only activity on the system side
- * immediately, which would delegate either to the unbundled chooser, or to a
- * (properly-inheriting) system ChooserActivity. This would have performance implications even
- * when the unbundling experiment is disabled.
- */
- protected void super_onRestoreInstanceState(Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
- }
-
- /**
- * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode
- * where we hand over to the unbundled chooser (while violating many of the invariants of a
- * typical ResolverActivity implementation). Subclasses running in this mode need to be able
- * to opt-out of the normal ResolverActivity behavior.
- *
- * TODO: this should be removed later on in the unbundling migration, when the springboard
- * activity no longer needs to derive from ResolverActivity. The hold-over design here is
- * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as
- * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity
- * implementations that depend on the invariants that are violated in the headless mode). If
- * necessary, we could instead consider using a springboard-only activity on the system side
- * immediately, which would delegate either to the unbundled chooser, or to a
- * (properly-inheriting) system ChooserActivity. This would have performance implications even
- * when the unbundling experiment is disabled.
- */
- public void super_onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- }
-
@Override
protected void onCreate(Bundle savedInstanceState) {
// Use a specialized prompt when we're handling the 'Home' app startActivity()
@@ -682,9 +602,7 @@ public class ResolverActivity extends Activity implements
mProfileSwitchMessage = null;
onTargetSelected(dri, false);
- if (!mAwaitingDelegateResponse) {
- finish();
- }
+ finish();
}
/**
@@ -974,7 +892,7 @@ public class ResolverActivity extends Activity implements
}
final Intent intent = getIntent();
if ((intent.getFlags() & FLAG_ACTIVITY_NEW_TASK) != 0 && !isVoiceInteraction()
- && !mResolvingHome && !mRetainInOnStop && !mAwaitingDelegateResponse) {
+ && !mResolvingHome && !mRetainInOnStop) {
// This resolver is in the unusual situation where it has been
// launched at the top of a new task. We don't let it be added
// to the recent tasks shown to the user, and we need to make sure
@@ -1143,9 +1061,7 @@ public class ResolverActivity extends Activity implements
mMultiProfilePagerAdapter.getActiveListAdapter().hasFilteredItem()
? MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_APP_FEATURED
: MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_NONE_FEATURED);
- if (!mAwaitingDelegateResponse) {
- finish();
- }
+ finish();
}
}
@@ -1458,15 +1374,6 @@ public class ResolverActivity extends Activity implements
.write();
}
-
- public boolean startAsCallerImpl(Intent intent, Bundle options, boolean ignoreTargetSecurity,
- int userId) {
- // Note: this method will be overridden in the delegate implementation to use the passed-in
- // permission token.
- startActivityAsCaller(intent, options, false, userId);
- return true;
- }
-
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
@@ -2374,9 +2281,7 @@ public class ResolverActivity extends Activity implements
.getItem(selections[0].getIndex());
if (ra.onTargetSelected(ti, false)) {
ra.mPickOptionRequest = null;
- if (!ra.mAwaitingDelegateResponse) {
- ra.finish();
- }
+ ra.finish();
}
}
}
diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
index dc53e77466ad..5ebc9154023c 100644
--- a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
+++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
@@ -173,9 +173,8 @@ public class DisplayResolveInfo implements TargetInfo, Parcelable {
@Override
public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
- // TODO: if the start-as-caller API no longer requires a permission token, this can go back
- // to inlining the real activity-start call, and we can remove startAsCallerImpl.
- return activity.startAsCallerImpl(mResolvedIntent, options, false, userId);
+ activity.startActivityAsCaller(mResolvedIntent, options, false, userId);
+ return true;
}
@Override
diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
index 8a19f2d2aa4e..015336388b5d 100644
--- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
@@ -241,7 +241,8 @@ public final class SelectableTargetInfo implements ChooserTargetInfo {
final boolean ignoreTargetSecurity = mSourceInfo != null
&& mSourceInfo.getResolvedComponentName().getPackageName()
.equals(mChooserTarget.getComponentName().getPackageName());
- return activity.startAsCallerImpl(intent, options, ignoreTargetSecurity, userId);
+ activity.startActivityAsCaller(intent, options, ignoreTargetSecurity, userId);
+ return true;
}
@Override
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 0ada13a73ad2..f19bfc669997 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -514,9 +514,10 @@ public final class SystemUiDeviceConfigFlags {
"is_nearby_share_first_target_in_ranked_app";
/**
- * (boolean) Whether to enable the new unbundled "delegate chooser" implementation.
+ * (boolean) Whether to enable the new unbundled sharesheet
+ * (com.android.intentresolver.ChooserActivity).
*/
- public static final String USE_DELEGATE_CHOOSER = "use_delegate_chooser";
+ public static final String USE_UNBUNDLED_SHARESHEET = "use_unbundled_sharesheet";
/**
* (string) Name of the default QR code scanner activity. On the eligible devices this activity
diff --git a/core/java/com/android/internal/inputmethod/InputBindResult.java b/core/java/com/android/internal/inputmethod/InputBindResult.java
index e83840177a73..f7341a5c4574 100644
--- a/core/java/com/android/internal/inputmethod/InputBindResult.java
+++ b/core/java/com/android/internal/inputmethod/InputBindResult.java
@@ -19,9 +19,11 @@ package com.android.internal.inputmethod;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.graphics.Matrix;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -202,12 +204,29 @@ public final class InputBindResult implements Parcelable {
*/
public final int sequence;
+ @Nullable
+ private final float[] mVirtualDisplayToScreenMatrixValues;
+
/**
* {@code true} if the IME explicitly specifies {@code suppressesSpellChecker="true"}.
*/
public final boolean isInputMethodSuppressingSpellChecker;
/**
+ * @return {@link Matrix} that corresponds to {@link #mVirtualDisplayToScreenMatrixValues}.
+ * {@code null} if {@link #mVirtualDisplayToScreenMatrixValues} is {@code null}.
+ */
+ @Nullable
+ public Matrix getVirtualDisplayToScreenMatrix() {
+ if (mVirtualDisplayToScreenMatrixValues == null) {
+ return null;
+ }
+ final Matrix matrix = new Matrix();
+ matrix.setValues(mVirtualDisplayToScreenMatrixValues);
+ return matrix;
+ }
+
+ /**
* Creates a new instance of {@link InputBindResult}.
*
* @param result A result code defined in {@link ResultCode}.
@@ -225,6 +244,7 @@ public final class InputBindResult implements Parcelable {
public InputBindResult(@ResultCode int result,
IInputMethodSession method, SparseArray<IInputMethodSession> accessibilitySessions,
InputChannel channel, String id, int sequence,
+ @Nullable Matrix virtualDisplayToScreenMatrix,
boolean isInputMethodSuppressingSpellChecker) {
this.result = result;
this.method = method;
@@ -232,6 +252,12 @@ public final class InputBindResult implements Parcelable {
this.channel = channel;
this.id = id;
this.sequence = sequence;
+ if (virtualDisplayToScreenMatrix == null) {
+ mVirtualDisplayToScreenMatrixValues = null;
+ } else {
+ mVirtualDisplayToScreenMatrixValues = new float[9];
+ virtualDisplayToScreenMatrix.getValues(mVirtualDisplayToScreenMatrixValues);
+ }
this.isInputMethodSuppressingSpellChecker = isInputMethodSuppressingSpellChecker;
}
@@ -258,6 +284,7 @@ public final class InputBindResult implements Parcelable {
}
id = source.readString();
sequence = source.readInt();
+ mVirtualDisplayToScreenMatrixValues = source.createFloatArray();
isInputMethodSuppressingSpellChecker = source.readBoolean();
}
@@ -268,6 +295,7 @@ public final class InputBindResult implements Parcelable {
public String toString() {
return "InputBindResult{result=" + getResultString() + " method=" + method + " id=" + id
+ " sequence=" + sequence
+ + " virtualDisplayToScreenMatrix=" + getVirtualDisplayToScreenMatrix()
+ " isInputMethodSuppressingSpellChecker=" + isInputMethodSuppressingSpellChecker
+ "}";
}
@@ -299,6 +327,7 @@ public final class InputBindResult implements Parcelable {
}
dest.writeString(id);
dest.writeInt(sequence);
+ dest.writeFloatArray(mVirtualDisplayToScreenMatrixValues);
dest.writeBoolean(isInputMethodSuppressingSpellChecker);
}
@@ -366,7 +395,7 @@ public final class InputBindResult implements Parcelable {
}
private static InputBindResult error(@ResultCode int result) {
- return new InputBindResult(result, null, null, null, null, -1, false);
+ return new InputBindResult(result, null, null, null, null, -1, null, false);
}
/**
diff --git a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
index f81fd376fef0..7f11e3018849 100644
--- a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
@@ -987,7 +987,8 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
return false;
}
- if (mParentInputMethodManager.getDisplayId() != imeDisplayId) {
+ if (mParentInputMethodManager.getDisplayId() != imeDisplayId
+ && !mParentInputMethodManager.hasVirtualDisplayToScreenMatrix()) {
// requestCursorUpdates() is not currently supported across displays.
return false;
}
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 06bc4b56901a..4f51a5ba1bd1 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -36,6 +36,7 @@ import android.os.Trace;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
+import android.util.StatsLog;
import android.view.Choreographer;
import android.view.FrameMetrics;
import android.view.SurfaceControl;
@@ -98,6 +99,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
private final ViewRootImpl.SurfaceChangedCallback mSurfaceChangedCallback;
private final Handler mHandler;
private final ChoreographerWrapper mChoreographer;
+ private final StatsLogWrapper mStatsLog;
private final Object mLock = InteractionJankMonitor.getInstance().getLock();
private final boolean mDeferMonitoring;
@@ -148,6 +150,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
@NonNull SurfaceControlWrapper surfaceControlWrapper,
@NonNull ChoreographerWrapper choreographer,
@Nullable FrameMetricsWrapper metrics,
+ @NonNull StatsLogWrapper statsLog,
int traceThresholdMissedFrames, int traceThresholdFrameTimeMillis,
@Nullable FrameTrackerListener listener, @NonNull Configuration config) {
mSurfaceOnly = config.isSurfaceOnly();
@@ -155,6 +158,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
mHandler = handler;
mChoreographer = choreographer;
mSurfaceControlWrapper = surfaceControlWrapper;
+ mStatsLog = statsLog;
mDeferMonitoring = config.shouldDeferMonitor();
// HWUI instrumentation init.
@@ -215,7 +219,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
if (!mMetricsFinalized) {
end(REASON_END_SURFACE_DESTROYED);
- finish(mJankInfos.size() - 1);
+ finish();
}
}
}, 50);
@@ -309,7 +313,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
// Waiting at most 10 seconds for all callbacks to finish.
mWaitForFinishTimedOut = () -> {
Log.e(TAG, "force finish cuj because of time out:" + mSession.getName());
- finish(mJankInfos.size() - 1);
+ finish();
};
mHandler.postDelayed(mWaitForFinishTimedOut, TimeUnit.SECONDS.toMillis(10));
notifyCujEvent(ACTION_SESSION_END);
@@ -426,51 +430,45 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
}
- /**
- * Finds the first index in {@link #mJankInfos} which happened on or after {@link #mEndVsyncId},
- * or -1 if the session hasn't ended yet.
- */
- private int getIndexOnOrAfterEnd() {
- if (mEndVsyncId == INVALID_ID || mMetricsFinalized) {
- return -1;
+ private boolean hasReceivedCallbacksAfterEnd() {
+ if (mEndVsyncId == INVALID_ID) {
+ return false;
}
JankInfo last = mJankInfos.size() == 0 ? null : mJankInfos.valueAt(mJankInfos.size() - 1);
if (last == null) {
- return -1;
+ return false;
}
if (last.frameVsyncId < mEndVsyncId) {
- return -1;
+ return false;
}
-
- int lastIndex = -1;
for (int i = mJankInfos.size() - 1; i >= 0; i--) {
JankInfo info = mJankInfos.valueAt(i);
if (info.frameVsyncId >= mEndVsyncId) {
- if (isLastIndexCandidate(info)) {
- lastIndex = i;
+ if (callbacksReceived(info)) {
+ return true;
}
- } else {
- break;
}
}
- return lastIndex;
+ return false;
}
private void processJankInfos() {
- int indexOnOrAfterEnd = getIndexOnOrAfterEnd();
- if (indexOnOrAfterEnd == -1) {
+ if (mMetricsFinalized) {
+ return;
+ }
+ if (!hasReceivedCallbacksAfterEnd()) {
return;
}
- finish(indexOnOrAfterEnd);
+ finish();
}
- private boolean isLastIndexCandidate(JankInfo info) {
+ private boolean callbacksReceived(JankInfo info) {
return mSurfaceOnly
? info.surfaceControlCallbackFired
: info.hwuiCallbackFired && info.surfaceControlCallbackFired;
}
- private void finish(int indexOnOrAfterEnd) {
+ private void finish() {
mHandler.removeCallbacks(mWaitForFinishTimedOut);
mWaitForFinishTimedOut = null;
mMetricsFinalized = true;
@@ -484,12 +482,15 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
int missedAppFramesCount = 0;
int missedSfFramesCount = 0;
- for (int i = 0; i <= indexOnOrAfterEnd; i++) {
+ for (int i = 0; i < mJankInfos.size(); i++) {
JankInfo info = mJankInfos.valueAt(i);
final boolean isFirstDrawn = !mSurfaceOnly && info.isFirstFrame;
if (isFirstDrawn) {
continue;
}
+ if (info.frameVsyncId > mEndVsyncId) {
+ break;
+ }
if (info.surfaceControlCallbackFired) {
totalFramesCount++;
boolean missedFrame = false;
@@ -541,7 +542,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
triggerPerfetto();
}
if (mSession.logToStatsd()) {
- FrameworkStatsLog.write(
+ mStatsLog.write(
FrameworkStatsLog.UI_INTERACTION_FRAME_INFO_REPORTED,
mSession.getStatsdInteractionType(),
totalFramesCount,
@@ -691,6 +692,13 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
}
+ public static class StatsLogWrapper {
+ public void write(int code,
+ int arg1, long arg2, long arg3, long arg4, long arg5, long arg6) {
+ FrameworkStatsLog.write(code, arg1, arg2, arg3, arg4, arg5, arg6);
+ }
+ }
+
/**
* A listener that notifies cuj events.
*/
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 5947e66b2d30..3da37f89f83e 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -385,7 +385,8 @@ public class InteractionJankMonitor {
synchronized (mLock) {
FrameTrackerListener eventsListener = (s, act) -> handleCujEvents(act, s);
return new FrameTracker(session, mWorker.getThreadHandler(),
- threadedRenderer, viewRoot, surfaceControl, choreographer, mMetrics,
+ threadedRenderer, viewRoot, surfaceControl, choreographer,
+ mMetrics, new FrameTracker.StatsLogWrapper(),
mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis,
eventsListener, config);
}
diff --git a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
index d0df45c9af65..525004a8b415 100644
--- a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
+++ b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
@@ -111,9 +111,9 @@ public class MobileRadioPowerCalculator extends PowerCalculator {
calculateApp(app, uid, total, query, keys);
}
- final long consumptionUC = batteryStats.getMobileRadioMeasuredBatteryConsumptionUC();
- final int powerModel = getPowerModel(consumptionUC, query);
- calculateRemaining(total, powerModel, batteryStats, rawRealtimeUs, consumptionUC);
+ final long totalConsumptionUC = batteryStats.getMobileRadioMeasuredBatteryConsumptionUC();
+ final int powerModel = getPowerModel(totalConsumptionUC, query);
+ calculateRemaining(total, powerModel, batteryStats, rawRealtimeUs, totalConsumptionUC);
if (total.remainingPowerMah != 0 || total.totalAppPowerMah != 0) {
builder.getAggregateBatteryConsumerBuilder(
@@ -187,12 +187,13 @@ public class MobileRadioPowerCalculator extends PowerCalculator {
private void calculateRemaining(PowerAndDuration total,
@BatteryConsumer.PowerModel int powerModel, BatteryStats batteryStats,
- long rawRealtimeUs, long consumptionUC) {
+ long rawRealtimeUs, long totalConsumptionUC) {
long signalTimeMs = 0;
double powerMah = 0;
if (powerModel == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) {
- powerMah = uCtoMah(consumptionUC);
+ powerMah = uCtoMah(totalConsumptionUC) - total.totalAppPowerMah;
+ if (powerMah < 0) powerMah = 0;
}
for (int i = 0; i < NUM_SIGNAL_STRENGTH_LEVELS; i++) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 89ac72255306..2f7c0152207f 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -16,9 +16,7 @@
package com.android.internal.policy;
-import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.N;
@@ -2261,7 +2259,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
attrs.type == TYPE_APPLICATION || attrs.type == TYPE_DRAWN_APPLICATION;
final WindowConfiguration winConfig = getResources().getConfiguration().windowConfiguration;
// Only a non floating application window on one of the allowed workspaces can get a caption
- if (!mWindow.isFloating() && isApplication && winConfig.hasWindowDecorCaption()) {
+ if (!mWindow.isFloating() && isApplication && winConfig.hasWindowDecorCaption()
+ && !CAPTION_ON_SHELL) {
// Dependent on the brightness of the used title we either use the
// dark or the light button frame.
if (decorCaptionView == null) {
@@ -2549,9 +2548,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
// Convert the DP elevation into physical pixels.
elevation = dipToPx(elevation);
mElevationAdjustedForStack = true;
- } else if (windowingMode == WINDOWING_MODE_PINNED) {
- elevation = dipToPx(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP);
- mElevationAdjustedForStack = true;
} else {
mElevationAdjustedForStack = false;
}
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index e2d250589a8f..fd8534d45b2b 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -101,10 +101,6 @@ public class TransitionAnimation {
private static final String DEFAULT_PACKAGE = "android";
- // TODO (b/215515255): remove once we full migrate to shell transitions
- private static final boolean SHELL_TRANSITIONS_ENABLED =
- SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
-
private final Context mContext;
private final String mTag;
@@ -259,9 +255,6 @@ public class TransitionAnimation {
resId = ent.array.getResourceId(animAttr, 0);
}
}
- if (!SHELL_TRANSITIONS_ENABLED) {
- resId = updateToLegacyIfNeeded(resId);
- }
resId = updateToTranslucentAnimIfNeeded(resId, transit);
if (ResourceId.isValid(resId)) {
return loadAnimationSafely(context, resId, mTag);
@@ -269,24 +262,6 @@ public class TransitionAnimation {
return null;
}
- /**
- * Replace animations that are not compatible with the legacy transition system with ones that
- * are compatible with it.
- * TODO (b/215515255): remove once we full migrate to shell transitions
- */
- private int updateToLegacyIfNeeded(int anim) {
- if (anim == R.anim.activity_open_enter) {
- return R.anim.activity_open_enter_legacy;
- } else if (anim == R.anim.activity_open_exit) {
- return R.anim.activity_open_exit_legacy;
- } else if (anim == R.anim.activity_close_enter) {
- return R.anim.activity_close_enter_legacy;
- } else if (anim == R.anim.activity_close_exit) {
- return R.anim.activity_close_exit_legacy;
- }
- return anim;
- }
-
/** Load animation by attribute Id from a specific AnimationStyle resource. */
@Nullable
public Animation loadAnimationAttr(String packageName, int animStyleResId, int animAttr,
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index 8430c0859bc9..8952474924bb 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -30,6 +30,7 @@ oneway interface IInputMethodClient {
void setActive(boolean active, boolean fullscreen, boolean reportToImeController);
void scheduleStartInputIfNecessary(boolean fullscreen);
void reportFullscreenMode(boolean fullscreen);
+ void updateVirtualDisplayToScreenMatrix(int bindSequence, in float[] matrixValues);
void setImeTraceEnabled(boolean enabled);
void throwExceptionFromSystem(String message);
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index c5346b95440b..616411fee5f2 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -69,6 +69,9 @@ interface IInputMethodManager {
// TODO(Bug 113914148): Consider removing this.
int getInputMethodWindowVisibleHeight(in IInputMethodClient client);
+ oneway void reportVirtualDisplayGeometryAsync(in IInputMethodClient parentClient,
+ int childDisplayId, in float[] matrixValues);
+
oneway void reportPerceptibleAsync(in IBinder windowToken, boolean perceptible);
/** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */
void removeImeSurface();
diff --git a/core/java/com/android/internal/widget/CachingIconView.java b/core/java/com/android/internal/widget/CachingIconView.java
index d1156979ee07..8ddd4ffd3065 100644
--- a/core/java/com/android/internal/widget/CachingIconView.java
+++ b/core/java/com/android/internal/widget/CachingIconView.java
@@ -122,7 +122,10 @@ public class CachingIconView extends ImageView {
public Runnable setImageIconAsync(@Nullable final Icon icon) {
resetCache();
Drawable drawable = loadSizeRestrictedIcon(icon);
- return () -> setImageDrawable(drawable);
+ if (drawable != null) {
+ return () -> setImageDrawable(drawable);
+ }
+ return super.setImageIconAsync(icon);
}
@Override
diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java
index ce27b346567b..c9953513a97a 100644
--- a/core/java/com/android/internal/widget/LocalImageResolver.java
+++ b/core/java/com/android/internal/widget/LocalImageResolver.java
@@ -37,12 +37,18 @@ public class LocalImageResolver {
private static final String TAG = "LocalImageResolver";
+ /** There's no max size specified, load at original size. */
+ public static final int NO_MAX_SIZE = -1;
+
@VisibleForTesting
static final int DEFAULT_MAX_SAFE_ICON_SIZE_PX = 480;
/**
* Resolve an image from the given Uri using {@link ImageDecoder} if it contains a
* bitmap reference.
+ * Negative or zero dimensions will result in icon loaded in its original size.
+ *
+ * @throws IOException if the icon could not be loaded.
*/
@Nullable
public static Drawable resolveImage(Uri uri, Context context) throws IOException {
@@ -63,8 +69,10 @@ public class LocalImageResolver {
* Get the drawable from Icon using {@link ImageDecoder} if it contains a bitmap reference, or
* using {@link Icon#loadDrawable(Context)} otherwise. This will correctly apply the Icon's,
* tint, if present, to the drawable.
+ * Negative or zero dimensions will result in icon loaded in its original size.
*
- * @return drawable or null if loading failed.
+ * @return drawable or null if the passed icon parameter was null.
+ * @throws IOException if the icon could not be loaded.
*/
@Nullable
public static Drawable resolveImage(@Nullable Icon icon, Context context) throws IOException {
@@ -76,8 +84,10 @@ public class LocalImageResolver {
* Get the drawable from Icon using {@link ImageDecoder} if it contains a bitmap reference, or
* using {@link Icon#loadDrawable(Context)} otherwise. This will correctly apply the Icon's,
* tint, if present, to the drawable.
+ * Negative or zero dimensions will result in icon loaded in its original size.
*
- * @throws IOException if the icon could not be loaded for whichever reason
+ * @return loaded icon or null if a null icon was passed as a parameter.
+ * @throws IOException if the icon could not be loaded.
*/
@Nullable
public static Drawable resolveImage(@Nullable Icon icon, Context context, int maxWidth,
@@ -144,19 +154,22 @@ public class LocalImageResolver {
@Nullable
private static Drawable resolveBitmapImage(Icon icon, Context context, int maxWidth,
int maxHeight) {
- Bitmap bitmap = icon.getBitmap();
- if (bitmap == null) {
- return null;
- }
- if (bitmap.getWidth() > maxWidth || bitmap.getHeight() > maxHeight) {
- Icon smallerIcon = icon.getType() == Icon.TYPE_ADAPTIVE_BITMAP
- ? Icon.createWithAdaptiveBitmap(bitmap) : Icon.createWithBitmap(bitmap);
- // We don't want to modify the source icon, create a copy.
- smallerIcon.setTintList(icon.getTintList())
- .setTintBlendMode(icon.getTintBlendMode())
- .scaleDownIfNecessary(maxWidth, maxHeight);
- return smallerIcon.loadDrawable(context);
+ if (maxWidth > 0 && maxHeight > 0) {
+ Bitmap bitmap = icon.getBitmap();
+ if (bitmap == null) {
+ return null;
+ }
+
+ if (bitmap.getWidth() > maxWidth || bitmap.getHeight() > maxHeight) {
+ Icon smallerIcon = icon.getType() == Icon.TYPE_ADAPTIVE_BITMAP
+ ? Icon.createWithAdaptiveBitmap(bitmap) : Icon.createWithBitmap(bitmap);
+ // We don't want to modify the source icon, create a copy.
+ smallerIcon.setTintList(icon.getTintList())
+ .setTintBlendMode(icon.getTintBlendMode())
+ .scaleDownIfNecessary(maxWidth, maxHeight);
+ return smallerIcon.loadDrawable(context);
+ }
}
return icon.loadDrawable(context);
@@ -202,7 +215,7 @@ public class LocalImageResolver {
// in some cases despite it not saying so. Rethrow it as an IOException to keep
// our API contract.
} catch (IOException | Resources.NotFoundException e) {
- Log.e(TAG, "Failed to load image drawable", e);
+ Log.d(TAG, "Couldn't use ImageDecoder for drawable, falling back to non-resized load.");
return null;
}
}
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 2a4f812eb1de..9e5f6ea666ba 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -59,6 +59,7 @@ per-file android_media_* = file:/media/java/android/media/OWNERS
per-file android_media_midi_* = file:/media/java/android/media/midi/OWNERS
per-file android_opengl_* = file:/opengl/java/android/opengl/OWNERS
per-file android_os_storage_* = file:/core/java/android/os/storage/OWNERS
+per-file android_os_Trace* = file:/TRACE_OWNERS
per-file android_se_* = file:/omapi/java/android/se/OWNERS
per-file android_security_* = file:/core/java/android/security/OWNERS
per-file android_view_* = file:/core/java/android/view/OWNERS
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp
index 24d35316ef20..eab4e1d744cf 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.cpp
+++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp
@@ -105,10 +105,11 @@ std::shared_ptr<InputApplicationHandle> android_view_InputApplicationHandle_getH
jobject android_view_InputApplicationHandle_fromInputApplicationInfo(
JNIEnv* env, gui::InputApplicationInfo inputApplicationInfo) {
- jobject binderObject = javaObjectForIBinder(env, inputApplicationInfo.token);
+ ScopedLocalRef<jobject> binderObject(env,
+ javaObjectForIBinder(env, inputApplicationInfo.token));
ScopedLocalRef<jstring> name(env, env->NewStringUTF(inputApplicationInfo.name.data()));
return env->NewObject(gInputApplicationHandleClassInfo.clazz,
- gInputApplicationHandleClassInfo.ctor, binderObject, name.get(),
+ gInputApplicationHandleClassInfo.ctor, binderObject.get(), name.get(),
inputApplicationInfo.dispatchingTimeoutMillis);
}
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index db92310f2a26..484d92820b86 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -261,8 +261,8 @@ jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowIn
}
LOG_ALWAYS_FATAL_IF(inputWindowHandle == nullptr,
"Failed to create new InputWindowHandle object.");
- env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.token,
- javaObjectForIBinder(env, windowInfo.token));
+ ScopedLocalRef<jobject> token(env, javaObjectForIBinder(env, windowInfo.token));
+ env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.token, token.get());
ScopedLocalRef<jstring> name(env, env->NewStringUTF(windowInfo.name.data()));
env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.name, name.get());
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsFlags,
@@ -317,8 +317,9 @@ jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowIn
ScopedLocalRef<jobject> matrixObj(env, AMatrix_newInstance(env, transformVals));
env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.transform, matrixObj.get());
+ ScopedLocalRef<jobject> windowToken(env, javaObjectForIBinder(env, windowInfo.windowToken));
env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.windowToken,
- javaObjectForIBinder(env, windowInfo.windowToken));
+ windowToken.get());
return inputWindowHandle;
}
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index 85fd5d99e473..734b6ca47660 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -82,6 +82,26 @@ static void android_os_Trace_nativeAsyncTraceEnd(JNIEnv* env, jclass,
});
}
+static void android_os_Trace_nativeAsyncTraceForTrackBegin(JNIEnv* env, jclass, jlong tag,
+ jstring trackStr, jstring nameStr,
+ jint cookie) {
+ withString(env, trackStr, [env, tag, nameStr, cookie](char* track) {
+ withString(env, nameStr, [tag, track, cookie](char* name) {
+ atrace_async_for_track_begin(tag, track, name, cookie);
+ });
+ });
+}
+
+static void android_os_Trace_nativeAsyncTraceForTrackEnd(JNIEnv* env, jclass, jlong tag,
+ jstring trackStr, jstring nameStr,
+ jint cookie) {
+ withString(env, trackStr, [env, tag, nameStr, cookie](char* track) {
+ withString(env, nameStr, [tag, track, cookie](char* name) {
+ atrace_async_for_track_end(tag, track, name, cookie);
+ });
+ });
+}
+
static void android_os_Trace_nativeSetAppTracingAllowed(JNIEnv*, jclass, jboolean allowed) {
atrace_update_tags();
}
@@ -132,6 +152,12 @@ static const JNINativeMethod gTraceMethods[] = {
{ "nativeAsyncTraceEnd",
"(JLjava/lang/String;I)V",
(void*)android_os_Trace_nativeAsyncTraceEnd },
+ { "nativeAsyncTraceForTrackBegin",
+ "(JLjava/lang/String;Ljava/lang/String;I)V",
+ (void*)android_os_Trace_nativeAsyncTraceForTrackBegin },
+ { "nativeAsyncTraceForTrackEnd",
+ "(JLjava/lang/String;Ljava/lang/String;I)V",
+ (void*)android_os_Trace_nativeAsyncTraceForTrackEnd },
{ "nativeInstant",
"(JLjava/lang/String;)V",
(void*)android_os_Trace_nativeInstant },
diff --git a/core/proto/android/app/activitymanager.proto b/core/proto/android/app/activitymanager.proto
index a21d1d4f0a85..8d8759f20854 100644
--- a/core/proto/android/app/activitymanager.proto
+++ b/core/proto/android/app/activitymanager.proto
@@ -35,4 +35,6 @@ enum UidObserverFlag {
UID_OBSERVER_FLAG_CACHED = 5;
// report uid capability has changed, original value is 1 << 5
UID_OBSERVER_FLAG_CAPABILITY = 6;
+ // report pid oom adj has changed, original value is 1 << 6
+ UID_OBSERVER_FLAG_PROC_OOM_ADJ = 7;
}
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 17dc4589d402..7205dd817eb5 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -779,6 +779,8 @@ message UidRecordProto {
CHANGE_CACHED = 3;
CHANGE_UNCACHED = 4;
CHANGE_CAPABILITY = 5;
+ CHANGE_PROCSTATE = 6;
+ CHANGE_PROCADJ = 7;
}
repeated Change last_reported_changes = 8;
optional int32 num_procs = 9;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0353e4be9972..976c02e95098 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1993,15 +1993,6 @@
android:label="@string/permlab_changeWifiState"
android:protectionLevel="normal" />
- <!-- Allows applications to enable/disable wifi auto join. This permission
- is used to let OEMs grant their trusted app access to a subset of privileged wifi APIs
- to improve wifi performance.
- <p>Not for use by third-party applications.
- @deprecated will be replaced with MANAGE_WIFI_NETWORK_SELECTION -->
- <permission android:name="android.permission.MANAGE_WIFI_AUTO_JOIN"
- android:protectionLevel="signature|privileged|knownSigner"
- android:knownCerts="@array/wifi_known_signers" />
-
<!-- This permission is used to let OEMs grant their trusted app access to a subset of
privileged wifi APIs to improve wifi performance. Allows applications to manage
Wi-Fi network selection related features such as enable or disable global auto-join,
@@ -2510,14 +2501,6 @@
<permission android:name="android.permission.TRIGGER_LOST_MODE"
android:protectionLevel="signature|role"/>
- <!-- @SystemApi Allows an application to instruct the framework to send location to the device
- admin when an organization-owned device is in lost mode.
- <p>Not for use by third-party applications.
- @hide
- -->
- <permission android:name="android.permission.SEND_LOST_MODE_LOCATION_UPDATES"
- android:protectionLevel="signature|privileged"/>
-
<!-- ================================== -->
<!-- Permissions for accessing hardware -->
<!-- ================================== -->
@@ -3752,6 +3735,12 @@
<permission android:name="android.permission.BIND_ATTESTATION_VERIFICATION_SERVICE"
android:protectionLevel="signature" />
+ <!-- Allows the caller to generate keymint keys with the INCLUDE_UNIQUE_ID tag, which
+ uniquely identifies the device via the attestation certificate.
+ @hide @TestApi -->
+ <permission android:name="android.permission.REQUEST_UNIQUE_ID_ATTESTATION"
+ android:protectionLevel="signature" />
+
<!-- ========================================= -->
<!-- Permissions for special development tools -->
<!-- ========================================= -->
@@ -6054,7 +6043,7 @@
generation service.
@hide <p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION"
- android:protectionLevel="signature|role" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an app to set the theme overlay in /vendor/overlay
being used.
diff --git a/core/res/res/anim/activity_close_enter_legacy.xml b/core/res/res/anim/activity_close_enter_legacy.xml
deleted file mode 100644
index 9fa7c5498ea6..000000000000
--- a/core/res/res/anim/activity_close_enter_legacy.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <scale
- android:fromXScale="1.1"
- android:toXScale="1"
- android:fromYScale="1.1"
- android:toYScale="1"
- android:pivotX="50%"
- android:pivotY="50%"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@interpolator/fast_out_extra_slow_in"
- android:duration="400"/>
-</set> \ No newline at end of file
diff --git a/core/res/res/anim/activity_close_exit_legacy.xml b/core/res/res/anim/activity_close_exit_legacy.xml
deleted file mode 100644
index 1599ae8cb19f..000000000000
--- a/core/res/res/anim/activity_close_exit_legacy.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false"
- android:zAdjustment="top">
- <alpha
- android:fromAlpha="1"
- android:toAlpha="0.0"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@interpolator/linear"
- android:startOffset="33"
- android:duration="50"/>
- <scale
- android:fromXScale="1"
- android:toXScale="0.9"
- android:fromYScale="1"
- android:toYScale="0.9"
- android:pivotX="50%"
- android:pivotY="50%"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@interpolator/fast_out_extra_slow_in"
- android:duration="400"/>
-</set>
diff --git a/core/res/res/anim/activity_open_enter_legacy.xml b/core/res/res/anim/activity_open_enter_legacy.xml
deleted file mode 100644
index 38d3e8ed06ce..000000000000
--- a/core/res/res/anim/activity_open_enter_legacy.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-/*
-** Copyright 2009, 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <alpha
- android:fromAlpha="0"
- android:toAlpha="1.0"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@interpolator/linear"
- android:startOffset="50"
- android:duration="50"/>
- <scale
- android:fromXScale="0.85"
- android:toXScale="1"
- android:fromYScale="0.85"
- android:toYScale="1"
- android:pivotX="50%"
- android:pivotY="50%"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@interpolator/fast_out_extra_slow_in"
- android:duration="400"/>
-</set>
diff --git a/core/res/res/anim/activity_open_exit_legacy.xml b/core/res/res/anim/activity_open_exit_legacy.xml
deleted file mode 100644
index 3865d2149f42..000000000000
--- a/core/res/res/anim/activity_open_exit_legacy.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-/*
-** Copyright 2009, 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
-
- <!-- Fade out, over a black surface, which simulates a black scrim -->
- <alpha
- android:fromAlpha="1"
- android:toAlpha="0.4"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@interpolator/linear"
- android:startOffset="83"
- android:duration="167"/>
-
- <scale
- android:fromXScale="1"
- android:toXScale="1.05"
- android:fromYScale="1"
- android:toYScale="1.05"
- android:pivotX="50%"
- android:pivotY="50%"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@interpolator/fast_out_extra_slow_in"
- android:duration="400"/>
-</set> \ No newline at end of file
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 99d878493748..5fa7457b2796 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Laat \'n program toe om toestemming te vra om batteryoptimerings vir daardie program ignoreer."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"navraag oor alle pakkette"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Laat \'n program toe om alle geïnstalleerde pakette te sien."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"kry toegang tot AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Gee ’n program toegang tot AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"kry toegang tot AdServices Attribution API\'s"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Gee ’n program toegang tot AdServices Attribution API\'s."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"kry toegang tot AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Gee ’n program toegang tot AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Klop twee keer vir zoembeheer"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Kon nie legstuk byvoeg nie."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Gaan"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Program is nie beskikbaar nie"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nie op die oomblik beskikbaar nie."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> is nie beskikbaar nie"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Jy kan nie nou toegang hiertoe op jou <xliff:g id="DEVICE">%1$s</xliff:g> kry nie. Probeer eerder op jou Android TV-toestel."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Jy kan nie nou toegang hiertoe op jou <xliff:g id="DEVICE">%1$s</xliff:g> kry nie. Probeer eerder op jou tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Jy kan nie nou toegang hiertoe op jou <xliff:g id="DEVICE">%1$s</xliff:g> kry nie. Probeer eerder op jou foon."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Gee <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> toegang tot alle toestelloglêers?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Net hierdie keer"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Moenie toelaat nie"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Toestelloglêers teken aan wat op jou toestel gebeur. Programme kan hierdie loglêers gebruik om kwessies op te spoor en reg te stel.\n\nSommige loglêers bevat dalk sensitiewe inligting en daarom moet jy toegang tot alle toestelloglêers net gee aan programme wat jy vertrou. \n\nAs jy nie vir hierdie program toegang tot alle toestelloglêers gee nie, het dit steeds toegang tot sy eie loglêers, en jou toestelvervaardiger het dalk steeds toegang tot sommige loglêers of inligting op jou toestel. Kom meer te wete"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Moenie weer wys nie"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wil <xliff:g id="APP_2">%2$s</xliff:g>-skyfies wys"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Wysig"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> werk tans op die agtergrond en gebruik batterykrag. Tik om na te gaan."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> werk al vir \'n lang tyd op die agtergrond. Tik om na te gaan."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Gaan aktiewe programme na"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Kan nie toegang tot kamera van hierdie toestel af kry nie"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Stelseltaal"</string>
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index a6b04c9c0246..4b4ceafaee89 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"አንድ መተግበሪያ ለዚያ መተግበሪያ የባትሪ ማትባቶችን ችላ ለማለት እንዲጠይቅ ይፈቅድለታል።"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"ሁሉንም ጥቅሎች ይጠይቁ"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"አንድ መተግበሪያ ሁሉንም የተጫኑ ጥቅሎችን እንዲያይ ይፈቅድለታል።"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"የAdServices ርዕሶች ኤፒአይን ይድረሱ"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"መተግበሪያ የAdServices ርዕሶች ኤፒአይን እንዲደርስ ይፈቅዳል።"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"የAdServices Attribution ኤፒአይን ይድረሱ"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"መተግበሪያ የAdServices ባለቤትነት ኤፒአይዎችን ለመድረስ ይፈቅዳል።"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"የAdServices ብጁ ታዳሚዎች ኤፒአይን ይድረሱ"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"መተግበሪያ የAdServices ብጁ ታዳሚዎች ኤፒአይን ለመድረስ ይፈቅዳል።"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ለአጉላ መቆጣጠሪያ ሁለት ጊዜ ነካ አድርግ"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"ምግብር ማከል አልተቻለም።"</string>
<string name="ime_action_go" msgid="5536744546326495436">"ሂድ"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"መተግበሪያ አይገኝም"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> አሁን አይገኝም።"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> አይገኝም"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ይህ በዚህ ጊዜ በእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> ላይ ሊደረስበት አይችልም። በምትኩ በAndroid TV መሣሪያዎ ላይ ይሞክሩ።"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ይህ በዚህ ጊዜ በእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> ላይ ሊደረስበት አይችልም። በምትኩ በጡባዊዎ ላይ ይሞክሩ።"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ይህ በዚህ ጊዜ በእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> ላይ ሊደረስበት አይችልም። በምትኩ በስልክዎ ላይ ይሞክሩ።"</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ሁሉንም የመሣሪያ ምዝግብ ማስታወሻዎች እንዲደርስ ይፈቀድለት?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"አሁን ብቻ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"አትፍቀድ"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"የመሣሪያ ምዝግብ ማስታወሻዎች በመሣሪያዎ ላይ ምን እንደሚከሰት ይመዘግባሉ። መተግበሪያዎች ችግሮችን ለማግኘት እና ለማስተካከል እነዚህን ምዝግብ ማስታወሻዎች መጠቀም ይችላሉ።\n\nአንዳንድ ምዝግብ ማስታወሻዎች ሚስጥራዊነት ያለው መረጃ ሊይዙ ይችላሉ፣ ስለዚህ የሚያምኗቸውን መተግበሪያዎች ብቻ ሁሉንም የመሣሪያ ምዝግብ ማስታወሻዎች እንዲደርሱ ይፍቀዱላቸው። \n\nይህ መተግበሪያ ሁሉንም የመሣሪያ ምዝግብ ማስታወሻዎች እንዲደርስ ካልፈቀዱለት አሁንም የራሱን ምዝግብ ማስታወሻዎች መድረስ ይችላል፣ እንዲሁም የእርስዎ መሣሪያ አምራች አሁንም አንዳንድ ምዝግብ ማስታወሻዎችን ወይም መረጃዎችን በመሣሪያዎ ላይ ሊደርስ ይችላል። የበለጠ መረዳት"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"ዳግም አታሳይ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> የ<xliff:g id="APP_2">%2$s</xliff:g> ቁራጮችን ማሳየት ይፈልጋል"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"አርትዕ"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ከበስተጀርባ በማሄድ ላይ ነው እና ባትሪ እየጨረሰ ነው። ለመገምገም መታ ያድርጉ።"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ከበስተጀርባ ለረጅም ጊዜ በማሄድ ላይ ነው። ለመገምገም መታ ያድርጉ።"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ንቁ መተግበሪያዎችን ይፈትሹ"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"ከዚህ መሣሪያ ሆኖ ካሜራን መድረስ አይቻልም"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"የስርዓት ቋንቋ"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 171a5a12e71a..a1c80090f14c 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -693,10 +693,8 @@
<string name="permdesc_readMediaAudio" msgid="5299772574434619399">"يسمح للتطبيق بقراءة الملفات الصوتية من مساحة التخزين المشتركة."</string>
<string name="permlab_readMediaVideo" msgid="7768003311260655007">"قراءة ملفات الفيديو من مساحة التخزين المشتركة"</string>
<string name="permdesc_readMediaVideo" msgid="3846400073770403528">"يسمح للتطبيق بقراءة ملفات الفيديو من مساحة التخزين المشتركة."</string>
- <!-- no translation found for permlab_readMediaImages (4057590631020986789) -->
- <skip />
- <!-- no translation found for permdesc_readMediaImages (5836219373138469259) -->
- <skip />
+ <string name="permlab_readMediaImages" msgid="4057590631020986789">"قراءة ملفات الصور من مساحة التخزين المشتركة"</string>
+ <string name="permdesc_readMediaImages" msgid="5836219373138469259">"يسمح هذا الإذن للتطبيق بقراءة ملفات الصور من مساحة التخزين المشتركة."</string>
<string name="permlab_sdcardWrite" msgid="4863021819671416668">"تعديل محتوى مساحة التخزين المشتركة أو حذفه"</string>
<string name="permdesc_sdcardWrite" msgid="8376047679331387102">"للسماح للتطبيق بالكتابة إلى محتوى مساحة التخزين المشتركة."</string>
<string name="permlab_use_sip" msgid="8250774565189337477">"‏إجراء/تلقي مكالمات SIP"</string>
@@ -1457,12 +1455,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"للسماح للتطبيق بطلب الإذن لتجاهل تحسينات البطارية في هذا التطبيق."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"البحث في كل الحِزم"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"يسمح هذا الإذن للتطبيق بعرض كل الحِزم المثبّتة."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"‏الوصول إلى واجهة AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"‏يتيح هذا الإذن للتطبيق الوصول إلى واجهة AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"‏الوصول إلى واجهات AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"‏يتيح هذا الإذن للتطبيق الوصول إلى واجهات AdServices Attribution API."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"‏الوصول إلى واجهة AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"‏يتيح هذا الإذن للتطبيق الوصول إلى واجهة AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"اضغط مرتين للتحكم في التكبير أو التصغير"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"تعذرت إضافة أداة."</string>
<string name="ime_action_go" msgid="5536744546326495436">"تنفيذ"</string>
@@ -1945,6 +1937,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"التطبيق غير متاح"</string>
<string name="app_blocked_message" msgid="542972921087873023">"تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> غير متاح الآن."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"تطبيق <xliff:g id="ACTIVITY">%1$s</xliff:g> غير متاح"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"‏لا يمكن الوصول إلى هذا التطبيق على <xliff:g id="DEVICE">%1$s</xliff:g> في الوقت الحالي. حاوِل الوصول إليه على جهاز Android TV بدلاً من ذلك."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"لا يمكن الوصول إلى هذا التطبيق على <xliff:g id="DEVICE">%1$s</xliff:g> في الوقت الحالي. حاوِل الوصول إليه على جهازك اللوحي بدلاً من ذلك."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"لا يمكن الوصول إلى هذا التطبيق على <xliff:g id="DEVICE">%1$s</xliff:g> في الوقت الحالي. حاوِل الوصول إليه على هاتفك بدلاً من ذلك."</string>
@@ -2040,7 +2034,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"هل تريد السماح لتطبيق <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> بالوصول إلى جميع سجلّات الجهاز؟"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"هذه المرَّة فقط"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"عدم السماح"</string>
- <!-- no translation found for log_access_confirmation_body (4483075525611652922) -->
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
<skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"عدم الإظهار مرة أخرى"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"يريد تطبيق <xliff:g id="APP_0">%1$s</xliff:g> عرض شرائح تطبيق <xliff:g id="APP_2">%2$s</xliff:g>."</string>
@@ -2275,7 +2269,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"يعمل تطبيق <xliff:g id="APP">%1$s</xliff:g> في الخلفية ويستنفد شحن البطارية. انقر لمراجعة الإعدادات."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"يعمل تطبيق <xliff:g id="APP">%1$s</xliff:g> في الخلفية لفترة طويلة. انقر لمراجعة الإعدادات."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"التحقّق من التطبيقات النشطة"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"لا يمكن الوصول إلى الكاميرا من هذا الجهاز."</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"لغة النظام"</string>
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 0d3f78d0da3c..5ae12f688463 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"কোনো এপক সেই এপ্‌টোৰ বাবে বেটাৰী অপ্টিমাইজেশ্বন উপেক্ষা কৰিবলৈ অনুমতি বিচাৰিবলৈ দিয়ে।"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"আটাইবোৰ পেকেজত প্ৰশ্ন সোধক"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"এপক আটাইবোৰ ইনষ্টল কৰি থোৱা পেকেজ চাবলৈ দিয়ে।"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API এক্সেছ কৰে"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"এটা এপ্লিকেশ্বনক AdServices Topics API এক্সেছ কৰিবলৈ অনুমতি দিয়ে।"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API এক্সেছ কৰে"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"এটা এপ্লিকেশ্বনক AdServices Attribution API এক্সেছ কৰিবলৈ অনুমতি দিয়ে।"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API এক্সেছ কৰে"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"এটা এপ্লিকেশ্বনক AdServices Custom Audiences API এক্সেছ কৰিবলৈ অনুমতি দিয়ে।"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"জুম নিয়ন্ত্ৰণ কৰিবলৈ দুবাৰ টিপক"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"ৱিজেট যোগ কৰিব পৰা নগ\'ল।"</string>
<string name="ime_action_go" msgid="5536744546326495436">"যাওক"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"এপ্‌টো উপলব্ধ নহয়"</string>
<string name="app_blocked_message" msgid="542972921087873023">"এই মুহূৰ্তত <xliff:g id="APP_NAME">%1$s</xliff:g> উপলব্ধ নহয়।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> উপলব্ধ নহয়"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"অনুমতিৰ প্ৰয়োজন"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"এইটো এতিয়া আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ত এক্সেছ কৰিব পৰা নাযায়। তাৰ পৰিৱৰ্তে আপোনাৰ Android TVত চেষ্টা কৰি চাওক।"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"এইটো এতিয়া আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ত এক্সেছ কৰিব পৰা নাযায়। তাৰ পৰিৱৰ্তে আপোনাৰ টেবলেটটোত চেষ্টা কৰি চাওক।"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"এইটো এতিয়া আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ত এক্সেছ কৰিব পৰা নাযায়। তাৰ পৰিৱৰ্তে আপোনাৰ ফ’নত চেষ্টা কৰি চাওক।"</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>ক আটাইবোৰ ডিভাইচৰ লগ এক্সেছ কৰাৰ অনুমতি প্ৰদান কৰিবনে?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"কেৱল এইবাৰৰ বাবে"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"অনুমতি নিদিব"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"আপোনাৰ ডিভাইচত কি কি ঘটে সেয়া ডিভাইচ লগে ৰেকৰ্ড কৰে। এপে সমস্যা বিচাৰিবলৈ আৰু সমাধান কৰিবলৈ এইসমূহ লগ ব্যৱহাৰ কৰিব পাৰে।\n\nকিছুমান লগত সংবেদনশীল তথ্য থাকিব পাৰে, গতিকে কেৱল আপুনি বিশ্বাস কৰা এপকহে আটাইবোৰ ডিভাইচ লগৰ এক্সেছৰ অনুমতি দিয়া উচিত। \n\nআপুনি যদি এই এপ্‌টোক আটাইবোৰ ডিভাইচৰ লগ এক্সেছ কৰাৰ অনুমতি নিদিয়ে, তেতিয়াও ই নিজৰ লগসমূহ এক্সেছ কৰিব পাৰিব আৰু আপোনাৰ ডিভাইচৰ নিৰ্মাতাই আপোনাৰ ডিভাইচটোত কিছু লগ অথবা তথ্য এক্সেছ কৰিবলৈ সক্ষম হ’ব। অধিক জানক"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"পুনৰ নেদেখুৱাব"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>এ <xliff:g id="APP_2">%2$s</xliff:g>ৰ অংশ দেখুওৱাব খুজিছে"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"সম্পাদনা কৰক"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> নেপথ্যত চলি আছে আৰু অত্যধিক বেটাৰী খৰচ কৰিছে। পৰ্যালোচনা কৰিবলৈ টিপক।"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> নেপথ্যত দীৰ্ঘ সময় ধৰি চলি আছে। পৰ্যালোচনা কৰিবলৈ টিপক।"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"সক্ৰিয় এপ্‌সমূহ পৰীক্ষা কৰক"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"এইটো ডিভাইচৰ পৰা কেমেৰা এক্সেছ কৰিব নোৱাৰি"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"ছিষ্টেমৰ ভাষা"</string>
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 905a21531fc8..d336d2e94a6b 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Tatareya optimallaşdırılmasını o tətbiq üçün iqnor edilməsinə icazə vermək məqsədilə soruşmağa tətbiqə icazə verilir."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"bütün paketlər üçün sorğu göndərin"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Tətbiqə bütün quraşdırılmış paketləri görmək icazəsi verir."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API\'ə giriş"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Tətbiqə AdServices Topics API\'ə giriş icazəsi verir."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API\'ə giriş"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Tətbiqə AdServices Attribution API\'ə giriş icazəsi verir."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API\'ə giriş"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Tətbiqə AdServices Custom Audiences API\'ə giriş icazəsi verir."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Zoom kontrolu üçün iki dəfə toxunun"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Widget əlavə edilə bilmədi."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Get"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Tətbiq əlçatan deyil"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hazırda əlçatan deyil."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> əlçatan deyil"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"İcazə tələb olunur"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Hazırda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızda buna giriş mümkün deyil. Android TV cihazınızda sınayın."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Hazırda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızda buna giriş mümkün deyil. Planşetinizdə sınayın."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Hazırda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızda buna giriş mümkün deyil. Telefonunuzda sınayın."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> tətbiqinin bütün cihaz qeydlərinə girişinə icazə verilsin?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Yalnız bu dəfə"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"İcazə verməyin"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Cihaz qeydləri cihazınızda baş verənləri qeyd edir. Tətbiqlər problemləri tapmaq və həll etmək üçün bu qeydlərdən istifadə edə bilər.\n\nBəzi qeydlərdə həssas məlumatlar ola bilər, ona görə də yalnız etibar etdiyiniz tətbiqlərin bütün cihaz qeydlərinə giriş etməsinə icazə verin. \n\nBu tətbiqin bütün cihaz qeydlərinə girişinə icazə verməsəniz, o, hələ də öz qeydlərinə giriş edə bilər və cihaz istehsalçınız hələ də cihazınızda bəzi qeydlərə və ya məlumatlara giriş edə bilər. Ətraflı məlumat"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Daha göstərməyin"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> tətbiqindən bölmələr göstərmək istəyir"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Redaktə edin"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> arxa fonda işləyir və enerjini tükədir. Nəzərdən keçirmək üçün toxunun."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> uzun müddət arxa fonda işləyir. Nəzərdən keçirmək üçün toxunun."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Aktiv tətbiqləri yoxlayın"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Bu cihazdan kameraya giriş mümkün deyil"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Sistem dili"</string>
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index f31a884782ab..e6e83b384d68 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1452,12 +1452,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Dozvoljava aplikaciji da traži dozvolu za ignorisanje optimizacija baterije za tu aplikaciju."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"slanje upita za sve pakete"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Dozvoljava aplikaciji da vidi sve instalirane pakete."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"pristup API-ju za teme usluga oglasa"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Dozvoljava aplikaciji da pristupa API-ju za teme usluga oglasa."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"pristup API-jima za pripisivanje usluga oglasa"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Dozvoljava aplikaciji da pristupa API-jima za distribuciju usluga oglasa."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"pristup API-ju za prilagođene publike usluga oglasa"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Dozvoljava aplikaciji da pristupa API-ju za prilagođene publike usluga oglasa."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Dodirnite dvaput za kontrolu zumiranja"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Nije moguće dodati vidžet."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Idi"</string>
@@ -1940,6 +1934,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – nije dostupno"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Potrebna je dozvola"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Ovoj aplikaciji trenutno ne može da se pristupi sa uređaja <xliff:g id="DEVICE">%1$s</xliff:g>. Probajte na Android TV uređaju."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Ovoj aplikaciji trenutno ne može da se pristupi sa uređaja <xliff:g id="DEVICE">%1$s</xliff:g>. Probajte na tabletu."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Ovoj aplikaciji trenutno ne može da se pristupi sa uređaja <xliff:g id="DEVICE">%1$s</xliff:g>. Probajte na telefonu."</string>
@@ -2035,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Želite da dozvolite aplikaciji <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> da pristupa svim evidencijama uređaja?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Samo ovaj put"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne dozvoli"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Evidencije uređaja registruju šta se dešava na uređaju. Aplikacije mogu da koriste te evidencije da bi pronašle i rešile probleme.\n\nNeke evidencije mogu da sadrže osetljive informacije, pa pristup svim evidencijama uređaja treba da dozvoljavate samo aplikacijama u koje imate poverenja. \n\nAko ne dozvolite ovoj aplikaciji da pristupa svim evidencijama uređaja, ona i dalje može da pristupa sopstvenim evidencijama, a proizvođač uređaja će možda i dalje moći da pristupa nekim evidencijama ili informacijama na uređaju. Saznajte više"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikazuj ponovo"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi da prikazuje isečke iz aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Izmeni"</string>
@@ -2269,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> troši bateriju u pozadini. Dodirnite da biste pregledali."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> je predugo pokrenuta u pozadini. Dodirnite da biste pregledali."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Proverite aktivne aplikacije"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Ne možete da pristupite kameri sa ovog uređaja"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Jezik sistema"</string>
</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 4b61b0de1f0a..500a94acbb2c 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1453,12 +1453,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Дазваляе праграме запытваць дазвол на ігнараванне аптымізацыі акумулятара для гэтай праграмы."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"запыт усіх пакетаў"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Дазваляе праграме выяўляць усе ўсталяваныя пакеты."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"доступ да AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Дазваляе праграме мець доступ да AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"доступ да AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Дазваляе праграме мець доступ да AdServices Attribution API."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"доступ да AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Дазваляе праграме мець доступ да AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Націсніце двойчы, каб кіраваць маштабаваннем"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Немагчыма дадаць віджэт."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Пачаць"</string>
@@ -1941,6 +1935,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Праграма недаступная"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" цяпер недаступная."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недаступна: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Не ўдаецца атрымаць доступ з вашай прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Паспрабуйце скарыстаць прыладу Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Не ўдаецца атрымаць доступ з вашай прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Паспрабуйце скарыстаць планшэт."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Не ўдаецца атрымаць доступ з вашай прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Паспрабуйце скарыстаць тэлефон."</string>
@@ -2036,7 +2032,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Дазволіць праграме \"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>\" мець доступ да ўсіх журналаў прылады?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Толькі ў гэты раз"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дазваляць"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Журналы прылад запісваюць усё, што адбываецца на вашай прыладзе. Праграмы выкарыстоўваюць гэтыя журналы для пошуку і выпраўлення памылак.\n\nУ некаторых журналах можа ўтрымлівацца канфідэнцыяльная інфармацыя, таму давайце доступ да ўсіх журналаў прылады толькі тым праграмам, якім вы давяраеце. \n\nКалі вы не дасце гэтай праграме доступу да ўсіх журналаў прылад, у яе ўсё роўна застанецца доступ да ўласных журналаў і для вытворцы вашай прылады будуць даступнымі некаторыя журналы і інфармацыя на вашай прыладзе. Даведацца больш"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Больш не паказваць"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Праграма <xliff:g id="APP_0">%1$s</xliff:g> запытвае дазвол на паказ зрэзаў праграмы <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Рэдагаваць"</string>
@@ -2270,7 +2267,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> працуе ў фонавым рэжыме і расходуе зарад акумулятара. Націсніце, каб праглядзець."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> працуе ў фонавым рэжыме працяглы час. Націсніце, каб праглядзець."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Праверце актыўныя праграмы"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"З гэтай прылады няма доступу да камеры."</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Сістэмная мова"</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 34d330c1343a..eb1571263e36 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Разрешава на дадено приложение да иска разрешение за пренебрегване на свързаните с него оптимизации на батерията."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"заявка за всички пакети"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Разрешава на приложението да вижда всички инсталирани пакети."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"достъп до API за теми в AdServices"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Позволява на приложението достъп до API за теми в AdServices."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"достъп до API за приписване в AdServices"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Позволява на приложението достъп до API за приписване в AdServices."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"достъп до API за персонализирани аудитории в AdServices"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Позволява на приложението достъп до API за персонализирани аудитории в AdServices."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Докоснете двукратно за управление на промяната на мащаба"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Приспособлението не можа да бъде добавено."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Старт"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Приложението не е достъпно"</string>
<string name="app_blocked_message" msgid="542972921087873023">"В момента няма достъп до <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> не е налице"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Понастоящем не може да се осъществи достъп от устройството ви <xliff:g id="DEVICE">%1$s</xliff:g>. Вместо това опитайте от устройството си с Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Понастоящем не може да се осъществи достъп от устройството ви <xliff:g id="DEVICE">%1$s</xliff:g>. Вместо това опитайте от таблета си."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Понастоящем не може да се осъществи достъп от устройството ви <xliff:g id="DEVICE">%1$s</xliff:g>. Вместо това опитайте от телефона си."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Да се разреши ли на <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> достъп до всички регистрационни файлове за устройството?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Само този път"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Забраняване"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"В регистрационните файлове за устройството се записва какво се извършва на него. Приложенията могат да използват тези регистрационни файлове, за да откриват и отстраняват проблеми.\n\nНякои регистрационни файлове за устройството може да съдържат поверителна информация, затова разрешавайте достъп до всички тях само на приложения, на които имате доверие. \n\nАко не разрешите на това приложение достъп до всички регистрационни файлове за устройството, то пак може да осъществява достъп до собствените си регистрационни файлове и производителят на устройството пак може да има достъп до някои регистрационни файлове или информация на устройството ви. Научете повече"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Да не се показва пак"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> иска да показва части от <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Редактиране"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> работи на заден план и изразходва батерия. Докоснете за преглед."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> работи на заден план от дълго време. Докоснете за преглед."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Проверете активните приложения"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Не може да се осъществи достъп до камерата от това устройство"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Системен език"</string>
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index f08c4a657684..981fbda23ae6 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"কোনো অ্যাপের জন্য ব্যাটারি অপ্টিমাইজেশন উপেক্ষা করতে সেটিকে অনুমতির চাওয়ার মঞ্জুরি দেয়৷"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"অন্যান্য সব প্যাকেজের তথ্য সম্পর্কিত কোয়েরি দেখুন"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"এটি কোনও অ্যাপকে সর্বদা ইনস্টল করা সব প্যাকেজ দেখতে অনুমতি দেয়।"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API অ্যাক্সেস করুন"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"এর মাধ্যমে কোনও অ্যাপ AdServices Custom Topics APIs অ্যাক্সেস করার অনুমতি পায়।"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution APIs অ্যাক্সেস করুন"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"এর মাধ্যমে কোনও অ্যাপ AdServices Attribution APIs অ্যাক্সেস করার অনুমতি পায়।"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API অ্যাক্সেস করুন"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"এর মাধ্যমে কোনও অ্যাপ AdServices Custom Attribution APIs অ্যাক্সেস করার অনুমতি পায়।"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"জুম নিয়ন্ত্রণের জন্য দুবার ট্যাপ করুন"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"উইজেট যোগ করা যায়নি৷"</string>
<string name="ime_action_go" msgid="5536744546326495436">"যান"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"অ্যাপ পাওয়া যাচ্ছে না"</string>
<string name="app_blocked_message" msgid="542972921087873023">"এই মুহূর্তে <xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপ পাওয়া যাচ্ছে না।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> উপলভ্য নেই"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"এই সময়ে আপনার <xliff:g id="DEVICE">%1$s</xliff:g>-এ এটি অ্যাক্সেস করা যাবে না। পরিবর্তে আপনার Android TV ডিভাইস ব্যবহার করে দেখুন।"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"এই সময়ে আপনার <xliff:g id="DEVICE">%1$s</xliff:g>-এ এটি অ্যাক্সেস করা যাবে না। পরিবর্তে আপনার ট্যাবলেটে ব্যবহার করে দেখুন।"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"এই সময়ে আপনার <xliff:g id="DEVICE">%1$s</xliff:g>-এ এটি অ্যাক্সেস করা যাবে না। পরিবর্তে আপনার ফোনে ব্যবহার করে দেখুন।"</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> অ্যাপকে ডিভাইসের সব লগ অ্যাক্সেসের অনুমতি দিতে চান?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"শুধুমাত্র এখন"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"অনুমতি দেবেন না"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"ডিভাইস লগে আপনার ডিভাইসে করা অ্যাক্টিভিটি রেকর্ড করা হয়। অ্যাপ সমস্যা খুঁজে তা সমাধান করতে এইসব লগ ব্যবহার করতে পারে।\n\nকিছু লগে সংবেদনশীল তথ্য থাকতে পারে, তাই বিশ্বাস করেন শুধুমাত্র এমন অ্যাপকেই সব ডিভাইসের লগ অ্যাক্সেসের অনুমতি দিন। \n\nআপনি এই অ্যাপকে ডিভাইসের সব লগ অ্যাক্সেস করার অনুমতি না দিলেও, এটি নিজের লগ অ্যাক্সেস করতে পারবে। এছাড়া, ডিভাইস প্রস্তুতকারকও আপনার ডিভাইসের কিছু লগ বা তথ্য হয়ত অ্যাক্সেস করতে পারবে। আরও জানুন"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"আর দেখতে চাই না"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> অ্যাপটি <xliff:g id="APP_2">%2$s</xliff:g> এর অংশ দেখাতে চায়"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"এডিট করুন"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ব্যাকগ্রাউন্ডে চলছে এবং এর ফলে ব্যাটারির চার্জ কমে যাচ্ছে। পর্যালোচনা করতে ট্যাপ করুন।"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> অনেকক্ষণ ধরে ব্যাকগ্রাউন্ডে চলছে। পর্যালোচনা করতে ট্যাপ করুন।"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"অ্যাক্টিভ অ্যাপ চেক করুন"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"এই ডিভাইস থেকে ক্যামেরা অ্যাক্সেস করা যাচ্ছে না"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"সিস্টেমের ভাষা"</string>
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index a2af26cac9b5..2114862b8c7d 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1349,7 +1349,7 @@
<string name="usb_supplying_notification_title" msgid="5378546632408101811">"Punjenje povezanog uređaja putem USB-a"</string>
<string name="usb_mtp_notification_title" msgid="1065989144124499810">"Uključen je način rada Prijenos fajlova putem USB-a"</string>
<string name="usb_ptp_notification_title" msgid="5043437571863443281">"Uključen je način rada PTP putem USB-a"</string>
- <string name="usb_tether_notification_title" msgid="8828527870612663771">"Uključen je način rada Povezivanje mobitela putem USB-a"</string>
+ <string name="usb_tether_notification_title" msgid="8828527870612663771">"Dijeljenje internetske veze putem USB-a je uključeno"</string>
<string name="usb_midi_notification_title" msgid="7404506788950595557">"Uključen je način rada MIDI putem USB-a"</string>
<string name="usb_accessory_notification_title" msgid="1385394660861956980">"Povezan je USB periferni uređaj"</string>
<string name="usb_notification_message" msgid="4715163067192110676">"Dodirnite za više opcija."</string>
@@ -1452,12 +1452,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Omogućava aplikaciji da traži odobrenje za zanemarivanje optimizacije baterije za tu aplikaciju."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"upit za sve pakete"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Omogućava aplikaciji da pregleda sve instalirane pakete."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"pristupi AdServices Topics API-ju"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Dozvoljava aplikaciji da pristupi AdServices Topics API-ju."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"pristupi AdServices Attribution API-ovima"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Dozvoljava aplikaciji da pristupi AdServices Attribution API-ovima."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"pristupi AdServices Custom Audiences API-ju"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Dozvoljava aplikaciji da pristupi AdServices Custom Audiences API-ju."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Dodirnite dvaput za kontrolu uvećanja"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Dodavanje vidžeta nije uspjelo."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Započni"</string>
@@ -1940,6 +1934,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Nedostupno: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Potrebno je dopuštenje"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Trenutno ne možete pristupiti ovoj aplikaciji na uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Umjesto toga pokušajte na uređaju Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Trenutno ne možete pristupiti ovoj aplikaciji na uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Umjesto toga pokušajte na tabletu."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Trenutno ne možete pristupiti ovoj aplikaciji na uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Umjesto toga pokušajte na telefonu."</string>
@@ -2035,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Dozvoliti aplikaciji <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> da pristupa svim zapisnicima uređaja?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Samo ovaj put"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nemoj dozvoliti"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Zapisnici uređaja bilježe šta se dešava na uređaju. Aplikacije mogu koristiti te zapisnike da pronađu i isprave probleme.\n\nNeki zapisnici mogu sadržavati osjetljive podatke. Zato pristup svim zapisnicima uređaja dozvolite samo aplikacijama kojima vjerujete. \n\nAko ne dozvolite ovoj aplikaciji da pristupa svim zapisnicima uređaja, ona i dalje može pristupati svojim zapisnicima i proizvođač uređaja će možda i dalje biti u stanju pristupiti nekim zapisnicima ili podacima na uređaju. Saznajte više"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikazuj ponovo"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi prikazati isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
@@ -2269,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> radi u pozadini i troši bateriju. Dodirnite da pregledate."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> dugo radi u pozadini. Dodirnite da pregledate."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Provjerite aktivne aplikacije"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Nije moguće pristupiti kameri s ovog uređaja"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Jezik sistema"</string>
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 4791579e0382..9722ef5cd9c6 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Permet que una aplicació demani permís per ignorar les optimitzacions de bateria per a l\'aplicació."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"consultar tots els paquets"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Permet que una aplicació vegi els paquets instal·lats."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"accedir a l\'API AdServices Topics"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Permet que una aplicació accedeixi a l\'API AdServices Topics."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"accedir a les API AdServices Attribution"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Permet que una aplicació accedeixi a les API AdServices Attribution."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"accedir a l\'API AdServices Custom Audiences"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Permet que una aplicació accedeixi a l\'API AdServices Custom Audiences."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Piqueu dos cops per controlar el zoom"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"No s\'ha pogut afegir el widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Ves"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"L\'aplicació no està disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Ara mateix, <xliff:g id="APP_NAME">%1$s</xliff:g> no està disponible."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no està disponible"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"En aquests moments, no es pot accedir a aquesta aplicació al dispositiu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho al dispositiu Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"En aquests moments, no es pot accedir a aquesta aplicació al dispositiu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho a la tauleta."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"En aquests moments, no es pot accedir a aquesta aplicació al dispositiu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho al telèfon."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Vols permetre que <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> accedeixi a tots els registres del dispositiu?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Només aquesta vegada"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"No permetis"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Els registres del dispositiu inclouen informació sobre tot allò que passa al teu dispositiu. Les aplicacions poden utilitzar aquests registres per detectar i corregir problemes.\n\nÉs possible que alguns registres continguin informació sensible; per això només has de donar-hi accés a les aplicacions de confiança. \n\nEncara que no permetis que aquesta aplicació pugui accedir a tots els registres del dispositiu, podrà accedir als seus propis registres. A més, és possible que el fabricant del dispositiu també tingui accés a alguns registres o a informació del teu dispositiu. Més informació"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"No tornis a mostrar"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vol mostrar porcions de l\'aplicació <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edita"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> s\'està executant en segon pla i esgotant la bateria. Toca per revisar-ho."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Fa molta estona que <xliff:g id="APP">%1$s</xliff:g> s\'està executant en segon pla. Toca per revisar-ho."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Consulta les aplicacions actives"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"No es pot accedir a la càmera des d\'aquest dispositiu"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Idioma del sistema"</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index dfe5dc868bcb..8bcb834b3b26 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1453,12 +1453,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Povoluje aplikaci požádat o oprávnění ignorovat optimalizaci využití baterie, která pro ni je nastavena."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"zjistit všechny balíčky"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Umožňuje aplikaci načíst všechny nainstalované balíčky."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"přístup k rozhraní AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Umožňuje aplikaci přístup k rozhraní AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"přístup k rozhraním AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Umožňuje aplikaci přístup k rozhraním AdServices Attribution API."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"přístup k rozhraní AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Umožňuje aplikaci přístup k rozhraní AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Poklepáním můžete ovládat přiblížení"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Widget nelze přidat."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Přejít"</string>
@@ -1941,6 +1935,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikace není k dispozici"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> v tuto chvíli není k dispozici."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> není k dispozici"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Tato položka na vašem zařízení <xliff:g id="DEVICE">%1$s</xliff:g> v tuto chvíli není k dispozici. Zkuste to na zařízení Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Tato položka na vašem zařízení <xliff:g id="DEVICE">%1$s</xliff:g> v tuto chvíli není k dispozici. Zkuste to na tabletu."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Tato položka na vašem zařízení <xliff:g id="DEVICE">%1$s</xliff:g> v tuto chvíli není k dispozici. Zkuste to na telefonu."</string>
@@ -2036,7 +2032,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Povolit aplikaci <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> přístup ke všem protokolům zařízení?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Pouze tentokrát"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nepovolovat"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Do protokolů zařízení se zaznamenává, co se na zařízení děje. Aplikace tyto protokoly mohou používat k vyhledání a odstranění problémů.\n\nNěkteré protokoly mohou zahrnovat citlivé údaje. Přístup k protokolům zařízení proto povolte pouze aplikacím, kterým důvěřujete. \n\nI když této aplikaci nepovolíte přístup ke všem protokolům zařízení, bude mít přístup ke svým vlastním protokolům a k některým protokolům nebo zařízením může mít přístup také výrobce zařízení. Další informace"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Příště nezobrazovat"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikace <xliff:g id="APP_0">%1$s</xliff:g> chce zobrazovat ukázky z aplikace <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Upravit"</string>
@@ -2270,7 +2267,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Aplikace <xliff:g id="APP">%1$s</xliff:g> je spuštěna na pozadí a vybíjí baterii. Klepnutím ji zkontrolujete."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Aplikace <xliff:g id="APP">%1$s</xliff:g> je už dlouhou dobu spuštěna na pozadí. Klepnutím ji zkontrolujete."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Zkontrolujte aktivní aplikace"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Z tohoto zařízení nelze získat přístup k fotoaparátu"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Jazyk systému"</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 2a9b49101805..5a2787d2d11b 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Gør det muligt for en app at bede om tilladelse til at ignorere batterioptimeringer for den pågældende app."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"forespørg om alle pakker"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Giver en app tilladelse til at se alle installerede pakker."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"få adgang til AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Tillader, at en app får adgang til AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"få adgang til AdServices Attribution API\'er"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Tillader, at en app får adgang til AdServices Attribution API\'er."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"få adgang til Services Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Tillader, at en app får adgang til AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Tryk to gange for zoomkontrol"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Widget kunne ikke tilføjes."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Gå"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgængelig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgængelig lige nu."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> er ikke understøttet"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Du har ikke adgang til denne app på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din Android TV-enhed i stedet."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Du har ikke adgang til denne app på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din tablet i stedet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Du har ikke adgang til denne app på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din telefon i stedet."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Vil du give <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> adgang til alle enhedslogs?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Kun denne gang"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Tillad ikke"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Enhedslogs registrerer, hvad der sker på din enhed. Apps kan bruge disse logs til at finde og løse problemer.\n\nNogle logs kan indeholde følsomme oplysninger, så giv kun apps, du har tillid til, adgang til alle enhedslogs. \n\nHvis du ikke giver denne app adgang til alle enhedslogs, kan den stadig tilgå sine egne logs, og producenten af din enhed kan muligvis fortsat tilgå visse logs eller oplysninger på din enhed. Få flere oplysninger"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Vis ikke igen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> anmoder om tilladelse til at vise eksempler fra <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Rediger"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> kører i baggrunden og dræner batteriet. Tryk for at gennemgå."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> har kørt i baggrunden i lang tid. Tryk for at gennemgå."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Tjek aktive apps"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Kameraet kan ikke tilgås fra denne enhed"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Systemsprog"</string>
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 46d662edde59..41f78e8e4a5b 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Erlaubt einer App, nach der Berechtigung zum Ignorieren der Akku-Leistungsoptimierungen zu fragen."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"Alle Pakete abfragen"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Ermöglicht der App, alle installierten Pakete zu sehen."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"Zugriff auf die AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Ermöglicht einer App den Zugriff auf die AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"Zugriff auf AdServices Attribution APIs"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Ermöglicht einer App den Zugriff auf AdServices Attribution APIs."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"Zugriff auf die AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Ermöglicht einer App den Zugriff auf die AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Für Zoomeinstellung zweimal berühren"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Widget konnte nicht hinzugefügt werden."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Los"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"App ist nicht verfügbar"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist derzeit nicht verfügbar."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nicht verfügbar"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Berechtigung erforderlich"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Auf deinem <xliff:g id="DEVICE">%1$s</xliff:g> ist derzeit kein Zugriff möglich. Versuche es stattdessen auf deinem Android TV-Gerät."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Auf deinem <xliff:g id="DEVICE">%1$s</xliff:g> ist derzeit kein Zugriff möglich. Versuche es stattdessen auf deinem Tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Auf deinem <xliff:g id="DEVICE">%1$s</xliff:g> ist derzeit kein Zugriff möglich. Versuche es stattdessen auf deinem Smartphone."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> den Zugriff auf alle Geräteprotokolle erlauben?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Nur dieses Mal"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nicht zulassen"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"In Geräteprotokollen wird aufgezeichnet, welche Aktionen auf deinem Gerät ausgeführt werden. Apps können diese Protokolle verwenden, um Probleme zu finden und zu beheben.\n\nEinige Protokolle enthalten unter Umständen vertrauliche Informationen. Daher solltest du nur vertrauenswürdigen Apps den Zugriff auf alle Geräteprotokolle gewähren. \n\nWenn du dieser App keinen Zugriff auf alle Geräteprotokolle gewährst, kann sie trotzdem auf ihre eigenen Protokolle zugreifen. Dein Gerätehersteller hat möglicherweise auch Zugriff auf einige Protokolle oder Informationen auf deinem Gerät. Weitere Informationen"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Nicht mehr anzeigen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> möchte Teile von <xliff:g id="APP_2">%2$s</xliff:g> anzeigen"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Bearbeiten"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> wird im Hintergrund ausgeführt und belastet den Akku. Zum Prüfen tippen."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> wird schon längere Zeit im Hintergrund ausgeführt. Zum Prüfen tippen."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Aktive Apps prüfen"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Von diesem Gerät aus ist kein Zugriff auf die Kamera möglich"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Systemsprache"</string>
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 6eccbd6de4ab..f4cb633ecec6 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Επιτρέπει σε μια εφαρμογή να ζητήσει άδεια για την αγνόηση βελτιστοποιήσεων της μπαταρίας για τη συγκεκριμένη εφαρμογή."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"υποβολή ερωτήματος σε όλα τα πακέτα"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Επιτρέπει σε μια εφαρμογή να βλέπει όλα τα εγκατεστημένα πακέτα."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"πρόσβαση σε API θεμάτων AdServices."</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Επιτρέπει σε μια εφαρμογή να αποκτήσει πρόσβαση σε API θεμάτων AdServices."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"πρόσβαση σε API απόδοσης AdServices"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Επιτρέπει σε μια εφαρμογή να αποκτήσει πρόσβαση σε API απόδοσης AdServices."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"πρόσβαση σε API προσαρμοσμένων κοινών AdServices"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Επιτρέπει σε μια εφαρμογή να αποκτήσει πρόσβαση σε API προσαρμοσμένων κοινών AdServices."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Πατήστε δύο φορές για έλεγχο εστίασης"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Δεν ήταν δυνατή η προσθήκη του γραφικού στοιχείου."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Μετάβαση"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Η εφαρμογή δεν είναι διαθέσιμη"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν είναι διαθέσιμη αυτήν τη στιγμή."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> δεν διατίθεται"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Δεν είναι δυνατή η πρόσβαση στη συγκεκριμένη εφαρμογή από τη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g> αυτήν τη στιγμή. Δοκιμάστε στη συσκευή Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Δεν είναι δυνατή η πρόσβαση στη συγκεκριμένη εφαρμογή από τη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g> αυτήν τη στιγμή. Δοκιμάστε στο tablet σας."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Δεν είναι δυνατή η πρόσβαση στη συγκεκριμένη εφαρμογή από τη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g> αυτήν τη στιγμή. Δοκιμάστε στο τηλέφωνό σας."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Να επιτρέπεται στην εφαρμογή <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> η πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής;"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Μόνο αυτήν τη φορά"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Να μην επιτραπεί"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Τα αρχεία καταγραφής συσκευής καταγράφουν ό,τι συμβαίνει στη συσκευή σας. Οι εφαρμογές μπορούν να χρησιμοποιούν αυτά τα αρχεία καταγραφής για να εντοπίζουν και να διορθώνουν ζητήματα.\n\nΟρισμένα αρχεία καταγραφής ενδέχεται να περιέχουν ευαίσθητες πληροφορίες, επομένως, επιτρέψτε την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής μόνο στις εφαρμογές που εμπιστεύεστε. \n\nΑν δεν επιτρέψετε σε αυτήν την εφαρμογή την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής, εξακολουθεί να έχει πρόσβαση στα δικά της αρχεία καταγραφής, ενώ ο κατασκευαστής της συσκευής σας ενδέχεται να εξακολουθεί να έχει πρόσβαση σε ορισμένα αρχεία καταγραφής ή πληροφορίες στη συσκευή σας. Μάθετε περισσότερα"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Να μην εμφανισ. ξανά"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Η εφαρμογή <xliff:g id="APP_0">%1$s</xliff:g> θέλει να εμφανίζει τμήματα της εφαρμογής <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Επεξεργασία"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Το <xliff:g id="APP">%1$s</xliff:g> εκτελείται στο παρασκήνιο και καταναλώνει μπαταρία. Έλεγχος."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> εκτελείται στο παρασκήνιο για πολύ ώρα. Πατήστε για έλεγχο."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Έλεγχος ενεργών εφαρμογών"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Δεν είναι δυνατή η πρόσβαση στην κάμερα από αυτήν τη συσκευή."</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Γλώσσα συστήματος"</string>
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 96369c4a5545..cdb3dd7b42c7 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Allows an app to ask for permission to ignore battery optimisations for that app."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"query all packages"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Allows an app to see all installed packages."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"access AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Allows an application to access AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"access AdServices Attribution APIs"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Allows an application to access AdServices Attribution APIs."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"access AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Allows an application to access AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Tap twice for zoom control"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Couldn\'t add widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Go"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Permission needed"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your Android TV device instead."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your tablet instead."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your phone instead."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Allow <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> to access all device logs?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Only this time"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs and your device manufacturer may still be able to access some logs or info on your device. Learn more"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> is running in the background and draining battery. Tap to review."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> is running in the background for a long time. Tap to review."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Check active apps"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Cannot access camera from this device"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"System language"</string>
</resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 5dfbd285a171..e816f162e0db 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Allows an app to ask for permission to ignore battery optimisations for that app."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"query all packages"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Allows an app to see all installed packages."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"access AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Allows an application to access AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"access AdServices Attribution APIs"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Allows an application to access AdServices Attribution APIs."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"access AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Allows an application to access AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Tap twice for zoom control"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Couldn\'t add widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Go"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Permission needed"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your Android TV device instead."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your tablet instead."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your phone instead."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Allow <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> to access all device logs?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Only this time"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs and your device manufacturer may still be able to access some logs or info on your device. Learn more"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> is running in the background and draining battery. Tap to review."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> is running in the background for a long time. Tap to review."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Check active apps"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Cannot access camera from this device"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"System language"</string>
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 9b79587f7104..63515c252154 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Allows an app to ask for permission to ignore battery optimisations for that app."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"query all packages"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Allows an app to see all installed packages."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"access AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Allows an application to access AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"access AdServices Attribution APIs"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Allows an application to access AdServices Attribution APIs."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"access AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Allows an application to access AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Tap twice for zoom control"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Couldn\'t add widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Go"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Permission needed"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your Android TV device instead."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your tablet instead."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your phone instead."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Allow <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> to access all device logs?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Only this time"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs and your device manufacturer may still be able to access some logs or info on your device. Learn more"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> is running in the background and draining battery. Tap to review."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> is running in the background for a long time. Tap to review."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Check active apps"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Cannot access camera from this device"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"System language"</string>
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index cef74809cd55..e2f9440fac87 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Allows an app to ask for permission to ignore battery optimisations for that app."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"query all packages"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Allows an app to see all installed packages."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"access AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Allows an application to access AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"access AdServices Attribution APIs"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Allows an application to access AdServices Attribution APIs."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"access AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Allows an application to access AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Tap twice for zoom control"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Couldn\'t add widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Go"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Permission needed"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your Android TV device instead."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your tablet instead."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your phone instead."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Allow <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> to access all device logs?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Only this time"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs and your device manufacturer may still be able to access some logs or info on your device. Learn more"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> is running in the background and draining battery. Tap to review."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> is running in the background for a long time. Tap to review."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Check active apps"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Cannot access camera from this device"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"System language"</string>
</resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 4f91ab0b2738..05545337303d 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‏‎‏‎‏‎‏‏‎‎‎‏‎‏‏‎‏‎‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‎‎‎‎‏‏‎‏‎‏‏‎‏‎‎‎Allows an app to ask for permission to ignore battery optimizations for that app.‎‏‎‎‏‎"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‎‎‎‏‏‎‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‎query all packages‎‏‎‎‏‎"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‏‎‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎Allows an app to see all installed packages.‎‏‎‎‏‎"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‎‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‏‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎access AdServices Topics API‎‏‎‎‏‎"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‏‎‏‎‎‎‎‏‎‎‏‎‏‏‎‎‏‏‏‏‏‎‎‎‎‏‎‎‏‎Allows an application to access AdServices Topics API.‎‏‎‎‏‎"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‏‏‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‎‏‏‎‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‏‎‎‏‏‎‏‎‏‎‎access AdServices Attribution APIs‎‏‎‎‏‎"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‏‎‎‎‎‎‎‎‎‏‎‏‏‏‏‎‎‎‎‎Allows an application to access AdServices Attribution APIs.‎‏‎‎‏‎"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‏‎‏‏‎‎‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‎‎‎access AdServices Custom Audiences API‎‏‎‎‏‎"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‎‏‎‏‎‏‎‏‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎Allows an application to access AdServices Custom Audiences API.‎‏‎‎‏‎"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎‏‎‏‎‏‏‏‏‎‏‏‎‎‎‎‏‏‏‎‏‎‎‏‎‏‎‎‎‎‎‏‎‎‎‏‏‏‎‎‏‏‎‎Tap twice for zoom control‎‏‎‎‏‎"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‎Couldn\'t add widget.‎‏‎‎‏‎"</string>
<string name="ime_action_go" msgid="5536744546326495436">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‏‎‎‎Go‎‏‎‎‏‎"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎App is not available‎‏‎‎‏‎"</string>
<string name="app_blocked_message" msgid="542972921087873023">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‏‏‎‎‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is not available right now.‎‏‎‎‏‎"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‏‏‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎‎‎‏‏‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="ACTIVITY">%1$s</xliff:g>‎‏‎‎‏‏‏‎ unavailable‎‏‎‎‏‎"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‎‎‏‏‎‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‎‎‎‎‎‎‎‎‏‎Permission needed‎‏‎‎‏‎"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎This can’t be accessed on your ‎‏‎‎‏‏‎<xliff:g id="DEVICE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ at this time. Try on your Android TV device instead.‎‏‎‎‏‎"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎This can’t be accessed on your ‎‏‎‎‏‏‎<xliff:g id="DEVICE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ at this time. Try on your tablet instead.‎‏‎‎‏‎"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‏‎‎‏‏‏‎‎‎‎‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‎‏‏‎‎‏‏‎‎‏‏‎‎‎‎‎‎‎‏‏‏‎‎‎‏‏‎‎This can’t be accessed on your ‎‏‎‎‏‏‎<xliff:g id="DEVICE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ at this time. Try on your phone instead.‎‏‎‎‏‎"</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‏‎‎‎‎‏‎‎‎‎‎‎‏‏‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‎‎‏‎‎‎Allow ‎‏‎‎‏‏‎<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ to access all device logs?‎‏‎‎‏‎"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‎‏‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‏‏‎‎‏‏‏‎‎‎‎‎Only this time‎‏‎‎‏‎"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‏‏‎‎‎‏‎‏‎Don’t allow‎‏‎‎‏‎"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‎‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‏‎‏‎‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‎‏‏‏‎‏‎‎Device logs record what happens on your device. Apps can use these logs to find and fix issues.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Some logs may contain sensitive info, so only allow apps you trust to access all device logs. ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎If you don’t allow this app to access all device logs, it can still access its own logs and your device manufacturer may still be able to access some logs or info on your device. Learn more‎‏‎‎‏‎"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‎‎‏‏‎‎‎‎‎‎Don’t show again‎‏‎‎‏‎"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‎‎‎‏‏‎‏‎‎‏‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="APP_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ wants to show ‎‏‎‎‏‏‎<xliff:g id="APP_2">%2$s</xliff:g>‎‏‎‎‏‏‏‎ slices‎‏‎‎‏‎"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‏‎‎‎‏‏‏‎‏‎‎‏‏‎‎‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‏‏‏‎‏‏‏‎Edit‎‏‎‎‏‎"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‎‎‏‎‎‏‎‎‏‎‎‏‎‏‎‏‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is running in the background and draining battery. Tap to review.‎‏‎‎‏‎"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‎‎‎‎‎‎‎‎‎‎‎‏‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‏‎‎‎‎‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is running in the background for a long time. Tap to review.‎‏‎‎‏‎"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‎‏‏‎‏‏‏‎‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‏‎‎‏‎‏‎‏‏‎‏‏‎‏‏‎‎‏‎‎‎Check active apps‎‏‎‎‏‎"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‎‎‎‎‎‏‎‎‏‎‎‏‎‏‎‏‎‏‏‏‎‎‏‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎Cannot access camera from this device‎‏‎‎‏‎"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‎‎‎‏‏‎‎System language‎‏‎‎‏‎"</string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index fb27592fdaca..db06ff278c69 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -615,7 +615,7 @@
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Se inhabilitó temporalmente el sensor."</string>
<string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"No se puede usar el sensor de huellas dactilares. Consulta a un proveedor de reparaciones."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
- <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar huella digital"</string>
+ <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar huella dactilar"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar bloqueo de huella dactilar o pantalla"</string>
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utiliza tu huella dactilar para continuar"</string>
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Usa tu huella dactilar o bloqueo de pantalla para continuar"</string>
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Permite que una app solicite permiso para ignorar las optimizaciones de la batería."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"Búsqueda de todos los paquetes"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Permite que una app vea todos los paquetes que se instalaron."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"acceder a la API de AdServices Topics"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Permite que una aplicación acceda a la API de AdServices Topics."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"acceder a las APIs de AdServices Attribution"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Permite que una aplicación acceda a las APIs de AdServices Attribution."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"acceder a la API de AdServices Custom Audiences"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Permite que una aplicación acceda a la API de AdServices Custom Audiences."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Presiona dos veces para obtener el control del zoom"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"No se pudo agregar el widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Ir"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"La app no está disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible en este momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no disponible"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Por el momento, no se puede acceder a esto en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Inténtalo en tu dispositivo Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Por el momento, no se puede acceder a esto en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Inténtalo en tu tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Por el momento, no se puede acceder a esto en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Inténtalo en tu teléfono."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"¿Quieres permitir que <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> acceda a todos los registros del dispositivo?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Solo esta vez"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"No permitir"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Los registros del dispositivo permiten documentar lo que sucede en él. Las apps pueden usar estos registros para encontrar y solucionar problemas.\n\nEs posible que algunos registros del dispositivo contengan información sensible, por lo que solo permitimos que accedan a todos ellos apps de tu confianza. \n\nSi no permites que esta app acceda a todos los registros del dispositivo, aún puede acceder a sus propios registros. Además, es posible que el fabricante del dispositivo acceda a algunos registros o información en tu dispositivo. Más información"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"No volver a mostrar"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quiere mostrar fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> se está ejecutando en segundo plano y está agotando la batería. Presiona para revisar."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Hace mucho tiempo que <xliff:g id="APP">%1$s</xliff:g> se está ejecutando en segundo plano. Presiona para revisar esta actividad."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Consulta las apps activas"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"No se puede acceder a la cámara desde este dispositivo"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Idioma del sistema"</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index d0568e07732e..dbaf2819a8c0 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Permite que una aplicación solicite permiso para ignorar las optimizaciones de la batería."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"consultar todos los paquetes"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Permite que una aplicación vea todos los paquetes instalados."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"acceder a la API AdServices Topics"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Permite que una aplicación acceda a la API AdServices Topics."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"acceder a las APIs AdServices Attribution"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Permite que una aplicación acceda a las APIs AdServices Attribution."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"acceder a la API AdServices Custom Audiences"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Permite que una aplicación acceda a la API AdServices Custom Audiences."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Da dos toques para acceder al control de zoom."</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"No se ha podido añadir el widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Ir"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"La aplicación no está disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"En estos momentos, <xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no disponible"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"En estos momentos, no se puede acceder a este contenido en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Prueba en tu dispositivo Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"En estos momentos, no se puede acceder a este contenido en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Prueba en tu tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"En estos momentos, no se puede acceder a este contenido en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Prueba en tu teléfono."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"¿Permitir que <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> acceda a todos los registros del dispositivo?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Solo esta vez"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"No permitir"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Los registros del dispositivo documentan lo que sucede en tu dispositivo. Las aplicaciones pueden usar estos registros para encontrar y solucionar problemas.\n\nComo algunos registros pueden contener información sensible, es mejor que solo permitas que accedan a ellos las aplicaciones en las que confíes. \n\nAunque no permitas que esta aplicación acceda a todos los registros del dispositivo, aún podrá acceder a sus propios registros. Además, es posible que el fabricante del dispositivo pueda acceder a algunos registros o información de tu dispositivo. Más información"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"No volver a mostrar"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quiere mostrar fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> se está ejecutando en segundo plano y agotando batería. Toca para revisarlo."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> lleva mucho tiempo ejecutándose en segundo plano. Toca para revisarlo."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Consultar aplicaciones activas"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"No se puede acceder a la cámara desde este dispositivo"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Idioma del sistema"</string>
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 7b14c953f516..8eea04870e08 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Lubab rakendusel küsida luba rakenduse aku optimeerimise eiramiseks."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"päringute esitamine kõikide pakettide kohta"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Võimaldab rakendusel näha kõiki installitud pakette."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"juurdepääs AdServices Topics API-dele"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Annab rakendusele juurdepääsu AdServices Topics API-dele."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"juurdepääs AdServices Attribution API-dele"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Annab rakendusele juurdepääsu AdServices Attribution API-dele."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"juurdepääs AdServices Custom Audiences API-dele"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Annab rakendusele juurdepääsu AdServices Custom Audiences API-dele."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Suumi kasutamiseks koputage kaks korda"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Vidinat ei saanud lisada."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Mine"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Rakendus ei ole saadaval"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole praegu saadaval."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ei ole saadaval"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Sellele ei pääse praegu teie seadmega (<xliff:g id="DEVICE">%1$s</xliff:g>) juurde. Proovige juurde pääseda oma Android TV seadmega."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Sellele ei pääse praegu teie seadmega (<xliff:g id="DEVICE">%1$s</xliff:g>) juurde. Proovige juurde pääseda oma tahvelarvutiga."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Sellele ei pääse praegu teie seadmega (<xliff:g id="DEVICE">%1$s</xliff:g>) juurde. Proovige juurde pääseda oma telefoniga."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Kas anda rakendusele <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> juurdepääs kõigile seadmelogidele?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Ainult see kord"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ära luba"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Seadmelogid jäädvustavad, mis teie seadmes toimub. Rakendused saavad neid logisid kasutada probleemide tuvastamiseks ja lahendamiseks.\n\nMõned logid võivad sisaldada tundlikku teavet, seega lubage juurdepääs kõigile seadmelogidele ainult rakendustele, mida usaldate. \n\nKui te ei luba sellel rakendusel kõigile seadmelogidele juurde pääseda, pääseb see siiski juurde oma logidele. Samuti võib teie seadme tootja teie seadmes siiski teatud logidele või teabele juurde pääseda. Lisateave"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ära kuva uuesti"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Rakendus <xliff:g id="APP_0">%1$s</xliff:g> soovib näidata rakenduse <xliff:g id="APP_2">%2$s</xliff:g> lõike"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Muuda"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> töötab taustal ja kulutab akut. Puudutage ülevaatamiseks."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> on taustal töötanud kaua aega. Puudutage ülevaatamiseks."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Vaadake aktiivseid rakendusi"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Sellest seadmest ei pääse kaamerale juurde"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Süsteemi keel"</string>
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index af1de8651ce5..4d8baccb6d6c 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Bateriaren optimizazioei ez ikusi egiteko baimena eskatzea baimentzen die aplikazioei."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"Kontsultatu pakete guztiak"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Instalatutako pakete guztiak ikusteko baimena ematen dio aplikazioari."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics APIa atzitu"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"AdServices Topics APIa atzitzeko baimena ematen die aplikazioei."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution APIak atzitu"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"AdServices Attribution APIak atzitzeko baimena ematen die aplikazioei."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences APIa atzitu"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"AdServices Custom Audiences APIa atzitzeko baimena ematen die aplikazioei."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Sakatu birritan zooma kontrolatzeko"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Ezin izan da widgeta gehitu."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Joan"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikazioa ez dago erabilgarri"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ez dago erabilgarri une honetan."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ez dago erabilgarri"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Une honetan, aplikazioa ezin da <xliff:g id="DEVICE">%1$s</xliff:g> erabilita atzitu. Gailu horren ordez, erabili Android TV gailua."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Une honetan, aplikazioa ezin da <xliff:g id="DEVICE">%1$s</xliff:g> erabilita atzitu. Gailu horren ordez, erabili tableta."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Une honetan, aplikazioa ezin da <xliff:g id="DEVICE">%1$s</xliff:g> erabilita atzitu. Gailu horren ordez, erabili telefonoa."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Gailuko erregistro guztiak atzitzeko baimena eman nahi diozu <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> aplikazioari?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Oraingoan soilik"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ez eman baimenik"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Gailuko erregistroetan gailuan gertatzen den guztia gordetzen da. Arazoak bilatu eta konpontzeko erabil ditzakete aplikazioek erregistro horiek.\n\nBaliteke erregistro batzuek kontuzko informazioa edukitzea. Beraz, eman gailuko erregistro guztiak atzitzeko baimena fidagarritzat jotzen dituzun aplikazioei bakarrik. \n\nNahiz eta gailuko erregistro guztiak atzitzeko baimena ez eman aplikazio honi, aplikazioak hari dagozkion erregistroak atzitu ahalko ditu, eta baliteke gailuaren fabrikatzaileak gailuko erregistro edo datu batzuk atzitu ahal izatea. Lortu informazio gehiago"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ez erakutsi berriro"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> aplikazioak <xliff:g id="APP_2">%2$s</xliff:g> aplikazioaren zatiak erakutsi nahi ditu"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editatu"</string>
@@ -2268,7 +2265,10 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g>, atzeko planoan exekutatzen, eta bateria xahutzen ari da. Sakatu berrikusteko."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> aplikazioak denbora asko darama atzeko planoan exekutatzen. Sakatu berrikusteko."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Ikusi zer aplikazio dauden aktibo"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Ezin da atzitu kamera gailu honetatik"</string>
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
+ <skip />
<!-- no translation found for system_locale_title (3978041860457277638) -->
<skip />
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 4c3a3fa06e7c..5c435a93b7e0 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -236,7 +236,7 @@
<string name="reboot_safemode_title" msgid="5853949122655346734">"راه‌اندازی مجدد در حالت امن"</string>
<string name="reboot_safemode_confirm" msgid="1658357874737219624">"آیا می‌خواهید با حالت امن راه‌اندازی مجدد کنید؟ با این کار همهٔ برنامه‌های شخص ثالثی که نصب کرده‌اید غیرفعال می‌شوند. با راه‌اندازی دوباره سیستم این برنامه‌ها دوباره بازیابی می‌شوند."</string>
<string name="recent_tasks_title" msgid="8183172372995396653">"اخیر"</string>
- <string name="no_recent_tasks" msgid="9063946524312275906">"‏برنامه‎های جدید موجود نیست."</string>
+ <string name="no_recent_tasks" msgid="9063946524312275906">"برنامه‌های جدید موجود نیست."</string>
<string name="global_actions" product="tablet" msgid="4412132498517933867">"گزینه‌های رایانهٔ لوحی"</string>
<string name="global_actions" product="tv" msgid="3871763739487450369">"‏گزینه‌های Android TV"</string>
<string name="global_actions" product="default" msgid="6410072189971495460">"گزینه‌های تلفن"</string>
@@ -366,7 +366,7 @@
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"مدیریت تماس‌های درحال انجام"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"به برنامه اجازه می‌دهد جزئیات تماس‌های درحال انجام در دستگاه را ببیند و این تماس‌ها را کنترل کند."</string>
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"خواندن پیام‌های پخش سلولی"</string>
- <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"‏به برنامه اجازه می‎دهد پیام‌های پخش سلولی دستگاه شما را بخواند. هشدارهای پخش سلولی در برخی از موقعیت‌های مکانی تحویل داده می‎شوند تا موقعیت‌های اضطراری را به شما اعلام کنند. وقتی پخش سلولی دریافت می‎شود، ممکن است برنامه‎های مخرب در عملکرد یا کارکرد دستگاه شما اختلال ایجاد کنند."</string>
+ <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"‏به برنامه اجازه می‎دهد پیام‌های پخش سلولی دستگاه شما را بخواند. هشدارهای پخش سلولی در برخی از موقعیت‌های مکانی تحویل داده می‎شوند تا موقعیت‌های اضطراری را به شما اعلام کنند. وقتی پخش سلولی دریافت می‎شود، ممکن است برنامه‌های مخرب در عملکرد یا کارکرد دستگاه شما اختلال ایجاد کنند."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"خواندن فیدهای مشترک"</string>
<string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"‏به برنامه اجازه می‎دهد تا جزئیات مربوط به فیدهای همگام شده کنونی را دریافت کند."</string>
<string name="permlab_sendSms" msgid="7757368721742014252">"ارسال و نمایش پیام‌های پیامک"</string>
@@ -377,11 +377,11 @@
<string name="permdesc_readSms" product="default" msgid="774753371111699782">"این برنامه می‌تواند همه پیامک‌های ذخیره‌شده در تلفن شما را بخواند."</string>
<string name="permlab_receiveWapPush" msgid="4223747702856929056">"‏دریافت پیام‌های نوشتاری (WAP)"</string>
<string name="permdesc_receiveWapPush" msgid="1638677888301778457">"‏به برنامه اجازه می‌دهد پیام‌های WAP را دریافت و پردازش کند. این مجوز می‌تواند پیام‌های ارسالی به شما را بدون نمایش آن‌ها به شما حذف یا کنترل کند."</string>
- <string name="permlab_getTasks" msgid="7460048811831750262">"‏بازیابی برنامه‎های در حال اجرا"</string>
+ <string name="permlab_getTasks" msgid="7460048811831750262">"بازیابی برنامه‌های در حال اجرا"</string>
<string name="permdesc_getTasks" msgid="7388138607018233726">"به برنامه امکان می‌دهد اطلاعات مربوط به کارهای در حال اجرای اخیر و کنونی را بازیابی کند. این ممکن است به برنامه امکان دهد به اطلاعات مربوط به برنامه‌هایی که در دستگاه استفاده می‌شوند دست یابد."</string>
<string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"مدیریت نمایه و مالکان دستگاه"</string>
<string name="permdesc_manageProfileAndDeviceOwners" msgid="7304240671781989283">"به برنامه‌ها امکان می‌دهد، مالکان نمایه و مالک دستگاه را تنظیم کنند."</string>
- <string name="permlab_reorderTasks" msgid="7598562301992923804">"‏تنظیم مجدد ترتیب برنامه‎های در حال اجرا"</string>
+ <string name="permlab_reorderTasks" msgid="7598562301992923804">"تنظیم مجدد ترتیب برنامه‌های در حال اجرا"</string>
<string name="permdesc_reorderTasks" msgid="8796089937352344183">"‏به برنامه اجازه می‎دهد تا کارها را به پیش‌زمینه و پس‌زمینه منتقل کند. برنامه‎ ممکن است بدون دخالت شما این کار را انجام دهد."</string>
<string name="permlab_enableCarMode" msgid="893019409519325311">"فعال کردن حالت خودرو"</string>
<string name="permdesc_enableCarMode" msgid="56419168820473508">"‏به برنامه اجازه می‎دهد تا حالت خودرو را فعال کند."</string>
@@ -402,7 +402,7 @@
<string name="permlab_getPackageSize" msgid="375391550792886641">"اندازه‌گیری اندازه فضای ذخیره‌سازی برنامه"</string>
<string name="permdesc_getPackageSize" msgid="742743530909966782">"‏به برنامه اجازه می‎دهد تا کدها، داده‎ها و اندازه‎های حافظهٔ پنهان خود را بازیابی کند"</string>
<string name="permlab_writeSettings" msgid="8057285063719277394">"تغییر تنظیمات سیستم"</string>
- <string name="permdesc_writeSettings" msgid="8293047411196067188">"‏به برنامه اجازه می‎دهد تا داده‎های تنظیم سیستم را تغییر دهد. برنامه‎های مخرب می‎توانند پیکربندی سیستم شما را خراب کنند."</string>
+ <string name="permdesc_writeSettings" msgid="8293047411196067188">"‏به برنامه اجازه می‎دهد تا داده‎های تنظیم سیستم را تغییر دهد. برنامه‌های مخرب می‎توانند پیکربندی سیستم شما را خراب کنند."</string>
<string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"اجرا شدن در هنگام راه‌اندازی"</string>
<string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"به برنامه اجازه می‌دهد که به محض پایان راه‌اندازی سیستم، راه‌اندازی شود. این ویژگی ممکن است باعث شود راه‌اندازی دستگاه مدت زمان بیشتری طول بکشد و به برنامه اجازه می‌دهد با همیشه درحال اجرا بودنش باعث کاهش سرعت کلی دستگاه شود."</string>
<string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"‏به برنامه اجازه می‌دهد به‌محض اتمام راه‌اندازی سیستم، خود را راه‌اندازی کند. ممکن است این مجوز باعث شود دستگاه Android TV آهسته‌تر راه‌اندازی شود و به برنامه اجازه می‌دهد با همیشه درحال اجرا بودن، سرعت کلی دستگاه را کاهش دهد."</string>
@@ -712,7 +712,7 @@
<string name="permlab_manageNetworkPolicy" msgid="6872549423152175378">"مدیریت خط‌مشی شبکه"</string>
<string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"‏به برنامه اجازه می‎دهد تا خط‌مشی‎های شبکه را مدیریت کند و قوانین خاص برنامه را تعیین کند."</string>
<string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"تغییر محاسبه استفاده از شبکه"</string>
- <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"‏به برنامه اجازه می‎دهد تا نحوه محاسبه کاربرد شبکه در برنامه را تغییر دهد. برای استفاده برنامه‎های عادی نیست."</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"‏به برنامه اجازه می‎دهد تا نحوه محاسبه کاربرد شبکه در برنامه را تغییر دهد. برای استفاده برنامه‌های عادی نیست."</string>
<string name="permlab_accessNotifications" msgid="7130360248191984741">"اعلان‌های دسترسی"</string>
<string name="permdesc_accessNotifications" msgid="761730149268789668">"به برنامه اجازه می‌دهد به بازیابی، بررسی و پاک کردن اعلان‌ها از جمله موارد پست شده توسط سایر برنامه‌ها بپردازد."</string>
<string name="permlab_bindNotificationListenerService" msgid="5848096702733262458">"اتصال به یک سرویس شنونده اعلان"</string>
@@ -1040,11 +1040,11 @@
<string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"‏به برنامه اجازه می‎دهد سابقه مرورگر یا نشانک‎های ذخیره‌شده در دستگاه Android TV را تغییر دهد. ممکن است به برنامه اجازه دهد داده‌های مرورگر را پاک کند یا تغییر دهد. توجه: ممکن است این مجوز توسط مرورگرهای شخص ثالث یا سایر برنامه‌های دارای قابلیت مرور وب اجرا نشود."</string>
<string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"به برنامه اجازه می‌دهد سابقه مرورگر یا نشانک‌های ذخیره‌شده در تلفن شما را تغییر دهد. این ممکن است به برنامه اجازه دهد داده‌های مرورگر را حذف کند یا تغییر دهد. توجه: این مجوز ممکن است توسط مرورگرهای شخص ثالث یا سایر برنامه‌های دارای قابلیت مرور وب قابل اجرا نباشد."</string>
<string name="permlab_setAlarm" msgid="1158001610254173567">"تنظیم زنگ"</string>
- <string name="permdesc_setAlarm" msgid="2185033720060109640">"‏به برنامه اجازه می‎دهد تا زنگی را در برنامه ساعت زنگدار نصب‌شده تنظیم کند. برخی از برنامه‎های ساعت زنگدار نمی‌‎توانند این ویژگی را اعمال کنند."</string>
+ <string name="permdesc_setAlarm" msgid="2185033720060109640">"‏به برنامه اجازه می‎دهد تا زنگی را در برنامه ساعت زنگدار نصب‌شده تنظیم کند. برخی از برنامه‌های ساعت زنگدار نمی‌‎توانند این ویژگی را اعمال کنند."</string>
<string name="permlab_addVoicemail" msgid="4770245808840814471">"افزودن پست صوتی"</string>
<string name="permdesc_addVoicemail" msgid="5470312139820074324">"به برنامه اجازه می‌دهد تا پیام‌ها را به صندوق ورودی پست صوتی شما اضافه کند."</string>
<string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"تغییر مجوزهای مکان جغرافیایی مرورگر"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"‏به برنامه اجازه می‎دهد تا مجوزهای جغرافیایی مرورگر را تغییر دهد. برنامه‎های مخرب می‎توانند از آن استفاده کنند تا اطلاعات موقعیت مکانی را به سایت‌های وب کتابخانه بفرستند."</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"‏به برنامه اجازه می‎دهد تا مجوزهای جغرافیایی مرورگر را تغییر دهد. برنامه‌های مخرب می‎توانند از آن استفاده کنند تا اطلاعات موقعیت مکانی را به سایت‌های وب کتابخانه بفرستند."</string>
<string name="save_password_message" msgid="2146409467245462965">"می‌خواهید مرورگر این گذرواژه را به خاطر داشته باشد؟"</string>
<string name="save_password_notnow" msgid="2878327088951240061">"اکنون نه"</string>
<string name="save_password_remember" msgid="6490888932657708341">"به خاطر سپردن"</string>
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"به یک برنامه اجازه می‌دهد جهت نادیده گرفتن بهینه‌سازی باتری برای خود مجوز درخواست کند."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"پُرسمان همه بسته‌ها"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"به برنامه اجازه می‌دهد همه بسته‌های نصب‌شده را ببیند."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"‏دسترسی به میانای برنامه‌سازی کاربردی AdServices Topics"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"‏به برنامه اجازه می‌دهد به میانای برنامه‌سازی کاربردی AdServices Topics دسترسی داشته باشد."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"‏دسترسی به میاناهای برنامه‌سازی کاربردی AdServices Attribution"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"‏به برنامه اجازه می‌دهد به میاناهای برنامه‌سازی کاربردی AdServices Attribution دسترسی داشته باشد."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"‏دسترسی به میانای برنامه‌سازی کاربردی AdServices Custom Audiences"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"‏به برنامه اجازه می‌دهد به میانای برنامه‌سازی کاربردی AdServices Custom Audiences دسترسی داشته باشد."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"برای کنترل بزرگ‌نمایی، دو بار ضربه بزنید"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"افزودن ابزارک انجام نشد."</string>
<string name="ime_action_go" msgid="5536744546326495436">"برو"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"برنامه در دسترس نیست"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> درحال‌حاضر در دسترس نیست."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> دردسترس نیست"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"‏درحال‌حاضر نمی‌توان در <xliff:g id="DEVICE">%1$s</xliff:g> شما به این برنامه دسترسی داشت. دسترسی به آن را در دستگاه Android TV امتحان کنید."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"درحال‌حاضر نمی‌توان در <xliff:g id="DEVICE">%1$s</xliff:g> شما به این برنامه دسترسی داشت. دسترسی به آن را در رایانه لوحی‌تان امتحان کنید."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"درحال‌حاضر نمی‌توان در <xliff:g id="DEVICE">%1$s</xliff:g> شما به این برنامه دسترسی داشت. دسترسی به آن را در تلفنتان امتحان کنید."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"به <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> اجازه می‌دهید به همه گزارش‌های دستگاه دسترسی داشته باشد؟"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"فقط این بار"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"مجاز نیست"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"گزارش‌های دستگاه آنچه را در دستگاهتان رخ می‌دهد ثبت می‌کند. برنامه‌ها می‌توانند از این گزارش‌ها برای پیدا کردن مشکلات و رفع آن‌ها استفاده کنند.\n\nممکن است برخی‌از گزارش‌ها حاوی اطلاعات حساس باشند، بنابراین فقط به برنامه‌های مورداعتمادتان اجازه دسترسی به همه گزارش‌های دستگاه را بدهید. \n\nاگر به این برنامه اجازه ندهید به همه گزارش‌های دستگاه دسترسی داشته باشد، همچنان می‌تواند به گزارش‌های خودش دسترسی داشته باشد، و سازنده دستگاهتان نیز ممکن است همچنان بتواند به برخی‌از گزارش‌ها یا اطلاعات در دستگاهتان دسترسی داشته باشد. بیشتر بدانید"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"دوباره نشان داده نشود"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> می‌خواهد تکه‌های <xliff:g id="APP_2">%2$s</xliff:g> را نشان دهد"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ویرایش"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"‫<xliff:g id="APP">%1$s</xliff:g> در پس‌زمینه اجرا می‌شود و شارژ باتری را تخلیه می‌کند. برای مرور، ضربه بزنید."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> برای مدتی طولانی در پس‌زمینه اجرا می‌شود. برای مرور، ضربه بزنید."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"بررسی برنامه‌های فعال"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"نمی‌توان از این دستگاه به دوربین دسترسی پیدا کرد"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"زبان سیستم"</string>
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 36d748c40936..4cb8c8c10208 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Sallii sovelluksen pyytää lupaa ohittaa tietyn sovelluksen akun optimoinnit."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"kaikkien pakettien näkeminen"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Antaa sovelluksen nähdä kaikki asennetut paketit."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"pääsy AdServices Topics API ‑rajapintoihin"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Sovellus saa pääsyn AdServices Topics API ‑rajapintoihin."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"pääsy AdServices Attribution API ‑rajapintoihin"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Sovellus saa pääsyn AdServices Attribution API ‑rajapintoihin."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"pääsy AdServices Custom Audiences API ‑rajapintoihin"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Sovellus saa pääsyn AdServices Custom Audiences API ‑rajapintoihin."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Hallitse zoomausta napauttamalla kahdesti"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Widgetin lisääminen epäonnistui."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Siirry"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Sovellus ei ole käytettävissä"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole nyt käytettävissä."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ei käytettävissä"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"<xliff:g id="DEVICE">%1$s</xliff:g> ei tällä hetkellä saa pääsyä sovellukseen. Kokeile striimausta Android TV ‑laitteella."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"<xliff:g id="DEVICE">%1$s</xliff:g> ei tällä hetkellä saa pääsyä sovellukseen. Kokeile striimausta tabletilla."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"<xliff:g id="DEVICE">%1$s</xliff:g> ei tällä hetkellä saa pääsyä sovellukseen. Kokeile striimausta puhelimella."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Saako <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> pääsyn kaikkiin laitelokeihin?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Vain tämän kerran"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Älä salli"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Laitteen tapahtumat tallentuvat laitelokeihin. Niiden avulla sovellukset voivat löytää ja korjata ongelmia.\n\nJotkin lokit voivat sisältää arkaluontoista tietoa, joten salli pääsy kaikkiin laitelokeihin vain sovelluksille, joihin luotat. \n\nJos et salli tälle sovellukselle pääsyä kaikkiin laitelokeihin, sillä on kuitenkin pääsy sen omiin lokeihin ja laitteen valmistajalla voi olla pääsy joihinkin lokeihin tai tietoihin laitteella. Lue lisää"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Älä näytä uudelleen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> haluaa näyttää osia sovelluksesta <xliff:g id="APP_2">%2$s</xliff:g>."</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Muokkaa"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> on käynnissä taustalla ja kuluttaa akkua. Tarkista napauttamalla."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> on ollut käynnissä taustalla pitkän aikaa. Tarkista napauttamalla."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Tarkista aktiiviset sovellukset"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Ei pääsyä kameraan tältä laitteelta"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Järjestelmän kieli"</string>
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index cb89659d1d81..32b0639eaa09 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Permet à une application de demander la permission d\'ignorer les optimisations de la pile."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"envoyer une requête à propos de tous les paquets"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Permet à une application de voir tous les paquets installés."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"accès à l\'API Topics d\'AdServices"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Autorise une application à accéder à l\'API Topics d\'AdServices."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"accès aux API Attribution d\'AdServices"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Autorise une application à accéder aux API Attribution d\'AdServices."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"accès à l\'API Custom Audiences d\'AdServices"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Autorise une application à accéder à l\'API Custom Audiences d\'AdServices."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Appuyer deux fois pour régler le zoom"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Impossible d\'ajouter le widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Aller"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"L\'application n\'est pas accessible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas accessible pour le moment."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non accessible"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Impossible d\'accéder à ce contenu sur votre appareil <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre appareil Android TV à la place."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Impossible d\'accéder à ce contenu sur votre appareil <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre tablette à la place."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Impossible d\'accéder à ce contenu sur votre appareil <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre téléphone à la place."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Autoriser <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> à accéder à l\'ensemble des journaux de l\'appareil?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Seulement cette fois"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne pas autoriser"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Les journaux de l\'appareil enregistrent ce qui se passe sur celui-ci. Les applications peuvent utiliser ces journaux pour trouver et résoudre des problèmes.\n\nCertains journaux peuvent contenir des renseignements confidentiels. N\'autorisez donc que les applications auxquelles vous faites confiance puisque celles-ci pourront accéder à l\'ensemble des journaux de l\'appareil. \n\nMême si vous n\'autorisez pas cette application à accéder à l\'ensemble des journaux de l\'appareil, elle aura toujours accès à ses propres journaux, et le fabricant de votre appareil sera toujours en mesure d\'accéder à certains journaux ou renseignements sur votre appareil. En savoir plus"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne plus afficher"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> souhaite afficher <xliff:g id="APP_2">%2$s</xliff:g> tranches"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Modifier"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> s\'exécute en arrière-plan et décharge la pile. Touchez pour examiner."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> s\'exécute en arrière-plan depuis longtemps. Touchez pour examiner."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Vérifier les applications actives"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Impossible d\'accéder à l\'appareil photo à partir de cet appareil"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Langue du système"</string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index eb7cc6707d56..859ff1387dae 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Autorise une application à demander l\'autorisation d\'ignorer les optimisations de batterie pour cette application."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"interroger tous les packages"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Autorise une appli à voir tous les packages installés."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"accéder à l\'API AdServices Topics"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Permet à une appli d\'accéder à l\'API AdServices Topics."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"accéder aux API AdServices Attribution"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Permet à une appli d\'accéder aux API AdServices Attribution."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"accéder à l\'API AdServices Custom Audiences"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Permet à une appli d\'accéder à l\'API AdServices Custom Audiences."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Appuyer deux fois pour régler le zoom"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Impossible d\'ajouter le widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"OK"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Application non disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas disponible pour le moment."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponible"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Actuellement, vous ne pouvez pas accéder à cette application sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez plutôt d\'y accéder sur votre appareil Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Actuellement, vous ne pouvez pas accéder à cette application sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez plutôt d\'y accéder sur votre tablette."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Actuellement, vous ne pouvez pas accéder à cette application sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez plutôt d\'y accéder sur votre téléphone."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Autoriser <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> à accéder à tous les journaux de l\'appareil ?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Cette fois seulement"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne pas autoriser"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Les journaux enregistrent ce qui se passe sur votre appareil. Les applis peuvent les utiliser pour rechercher et résoudre les problèmes.\n\nCertains journaux pouvant contenir des infos sensibles, autorisez uniquement les applis de confiance à accéder à tous les journaux de l\'appareil. \n\nSi vous refusez à cette appli l\'accès à tous les journaux de l\'appareil, elle a quand même accès aux siens, et le fabricant de l\'appareil peut accéder à certains journaux ou certaines infos sur votre appareil. En savoir plus"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne plus afficher"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> souhaite afficher des éléments de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Modifier"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> s\'exécute en arrière-plan et décharge la batterie. Appuyez ici pour en savoir plus."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> s\'exécute en arrière-plan depuis longtemps. Appuyez ici pour en savoir plus."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Vérifier les applis actives"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Impossible d\'accéder à l\'appareil photo depuis cet appareil"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Langue du système"</string>
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index d50699aba13e..cf0ebb6c46ff 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Fai que unha aplicación poida solicitar permiso para ignorar as optimizacións da batería."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"consultar todos os paquetes"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Permite que unha aplicación consulte todos os paquetes instalados."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"acceder a AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Permite que unha aplicación acceda a AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"acceder ás AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Permite que unha aplicación acceda ás AdServices Attribution API."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"acceder a AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Permite que unha aplicación acceda a AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Toca dúas veces para controlar o zoom"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Non se puido engadir o widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Ir"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"A aplicación non está dispoñible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"A aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> non está dispoñible neste momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non está dispoñible"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Nestes momentos, non podes acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde o dispositivo con Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Nestes momentos, non podes acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde a tableta."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Nestes momentos, non podes acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde o teléfono."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Queres permitir que a aplicación <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> acceda a todos os rexistros do dispositivo?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Só esta vez"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Non permitir"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Os rexistros do dispositivo dan conta do que ocorre neste. As aplicacións poden usalos para buscar problemas e solucionalos.\n\nAlgúns poden conter información confidencial, polo que che recomendamos que só permitas que accedan a todos os rexistros do dispositivo as aplicacións nas que confíes. \n\nEsta aplicación pode acceder aos seus propios rexistros aínda que non lle permitas acceder a todos, e é posible que o fabricante do teu dispositivo teña acceso a algúns rexistros ou á información do teu dispositivo. Máis información"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Non amosar outra vez"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quere mostrar fragmentos de aplicación de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> está executándose en segundo plano e consumindo batería. Toca para revisalo."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> leva moito tempo executándose en segundo plano. Toca para revisalo."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Comprobar aplicacións activas"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Non se pode acceder á cámara desde este dispositivo"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Idioma do sistema"</string>
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 4186f9b0a2dd..2e02dae4bc13 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"ઍપ્લિકેશનને તે ઍપ્લિકેશન માટે બૅટરી ઓપ્ટિમાઇઝેશન્સને અવગણવાની પરવાનગી આપવા માટે પૂછવાની મંજૂરી આપે છે."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"બધા પૅકેજ જુઓ"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"કોઈ ઍપને ઇન્સ્ટૉલ કરેલા બધા પૅકેજ જોવાની મંજૂરી આપે છે."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API ઍક્સેસ કરો"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"ઍપ્લિકેશનને AdServices Topics API ઍક્સેસ કરવાની મંજૂરી આપે છે."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution APIs ઍક્સેસ કરો"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"ઍપ્લિકેશનને AdServices Attribution APIs ઍક્સેસ કરવાની મંજૂરી આપે છે."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API ઍક્સેસ કરો"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"ઍપ્લિકેશનને AdServices Custom Audiences API ઍક્સેસ કરવાની મંજૂરી આપે છે."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ઝૂમ નિયંત્રણ માટે બેવાર ટૅપ કરો"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"વિજેટ ઉમેરી શકાયું નથી."</string>
<string name="ime_action_go" msgid="5536744546326495436">"જાઓ"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ઍપ ઉપલબ્ધ નથી"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> હાલમાં ઉપલબ્ધ નથી."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ઉપલબ્ધ નથી"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"પરવાનગી જરૂરી છે"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"અત્યારે આને તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પર ઍક્સેસ કરી શકાતી નથી. તેના બદલે તમારા Android TV ડિવાઇસ પર પ્રયાસ કરો."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"અત્યારે આને તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પર ઍક્સેસ કરી શકાતી નથી. તેના બદલે તમારા ટૅબ્લેટ પર પ્રયાસ કરો."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"અત્યારે આને તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પર ઍક્સેસ કરી શકાતી નથી. તેના બદલે તમારા ફોન પર પ્રયાસ કરો."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>ને ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી આપવી છે?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"માત્ર આ વખતે"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"મંજૂરી આપશો નહીં"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"તમારા ડિવાઇસ પર થતી કામગીરીને ડિવાઇસ લૉગ રેકોર્ડ કરે છે. ઍપ આ લૉગનો ઉપયોગ સમસ્યાઓ શોધી તેનું નિરાકરણ કરવા માટે કરી શકે છે.\n\nઅમુક લૉગમાં સંવેદનશીલ માહિતી હોઈ શકે, આથી ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી માત્ર તમારી વિશ્વાસપાત્ર ઍપને જ આપો. \n\nતમે આ ઍપને ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી નહીં આપી હોય, તો પણ તે તેના પોતાના લૉગ ઍક્સેસ કરી શકે છે અને તમારા ડિવાઇસના ઉત્પાદક હજુ પણ તમારા ડિવાઇસ પર અમુક લૉગ અથવા માહિતી ઍક્સેસ કરી શકે તેમ બની શકે છે. વધુ જાણો"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"ફરીથી બતાવશો નહીં"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>એ <xliff:g id="APP_2">%2$s</xliff:g> સ્લાઇસ બતાવવા માગે છે"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ફેરફાર કરો"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ઍપ બૅકગ્રાઉન્ડમાં ચાલી રહી છે અને અતિશય બૅટરી વાપરી રહી છે. રિવ્યૂ કરવા માટે ટૅપ કરો."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> લાંબા સમયથી બૅકગ્રાઉન્ડમાં ચાલી રહી છે. રિવ્યૂ કરવા માટે ટૅપ કરો."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"સક્રિય ઍપ ચેક કરો"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"આ ડિવાઇસમાંથી કૅમેરા ઍક્સેસ કરી શકાતો નથી"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"સિસ્ટમની ભાષા"</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 8f3337f0930b..d44b55c8eba5 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"किसी ऐप्लिकेशन को उस ऐप्लिकेशन के लिए बैटरी ऑप्टिमाइज़ेशन पर ध्यान ना देने की अनुमति के लिए पूछने देता है."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"डिवाइस पर इंस्टॉल किए गए सभी पैकेज देखें"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"यह किसी ऐप्लिकेशन को, डिवाइस पर इंस्टॉल किए गए सभी पैकेज देखने की अनुमति देता है."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices टॉपिक एपीआई को ऐक्सेस करें"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"इससे किसी ऐप्लिकेशन को AdServices टॉपिक एपीआई को ऐक्सेस करने की अनुमति मिलती है."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices एट्रिब्यूशन एपीआई को ऐक्सेस करें"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"इससे किसी ऐप्लिकेशन को AdServices एट्रिब्यूशन एपीआई को ऐक्सेस करने की अनुमति मिलती है."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices कस्टम ऑडियंस एपीआई को ऐक्सेस करें"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"इससे किसी ऐप्लिकेशन को AdServices कस्टम ऑडियंस एपीआई को ऐक्सेस करने की अनुमति मिलती है."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ज़ूम नियंत्रण के लिए दो बार टैप करें"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"विजेट नहीं जोड़ा जा सका."</string>
<string name="ime_action_go" msgid="5536744546326495436">"जाएं"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ऐप्लिकेशन उपलब्ध नहीं है"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> इस समय उपलब्ध नहीं है."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध नहीं है"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"अनुमति ज़रूरी है"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"इस समय, आपके <xliff:g id="DEVICE">%1$s</xliff:g> पर इसे ऐक्सेस नहीं किया जा सकता. इसके बजाय, अपने Android TV डिवाइस पर कोशिश करें."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"इस समय, आपके <xliff:g id="DEVICE">%1$s</xliff:g> पर इसे ऐक्सेस नहीं किया जा सकता. इसके बजाय, अपने टैबलेट पर कोशिश करें."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"इस समय, आपके <xliff:g id="DEVICE">%1$s</xliff:g> पर इसे ऐक्सेस नहीं किया जा सकता. इसके बजाय, अपने फ़ोन पर कोशिश करें."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"क्या <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> को डिवाइस लॉग का ऐक्सेस देना है?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"सिर्फ़ इस बार"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"अनुमति न दें"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"डिवाइस लॉग में आपके डिवाइस पर की गई कार्रवाइयां रिकॉर्ड होती हैं. ऐप्लिकेशन, इन लॉग का इस्तेमाल गड़बड़ियां ढूंढने और उन्हें सही करने के लिए करता है.\n\nकुछ लॉग में संवेदनशील जानकारी हो सकती है. इसलिए, सिर्फ़ भरोसेमंद ऐप्लिकेशन को डिवाइस लॉग का ऐक्सेस दें. \n\nअगर इस ऐप्लिकेशन को डिवाइस लॉग का ऐक्सेस नहीं दिया जाता है, तब भी यह अपने डिवाइस लॉग को ऐक्सेस कर सकता है. इसके अलावा, डिवाइस को बनाने वाली कंपनी अब भी डिवाइस के कुछ लॉग और जानकारी को ऐक्सेस कर सकती है. ज़्यादा जानें"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"फिर से न दिखाएं"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>, <xliff:g id="APP_2">%2$s</xliff:g> के हिस्से (स्लाइस) दिखाना चाहता है"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"बदलाव करें"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> बैकग्राउंड में चल रहा है और बैटरी खर्च कर रहा है. देखने के लिए टैप करें."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> बैकग्राउंड में बहुत देर से चल रहा है. देखने के लिए टैप करें."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"चालू ऐप्लिकेशन देखें"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"इस डिवाइस से कैमरे का इस्तेमाल नहीं किया जा सकता"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"सिस्टम की भाषा"</string>
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 52f7ea2fd46d..07bc84ec3e24 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1452,12 +1452,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Aplikaciji omogućuje da traži dopuštenje za zanemarivanje optimizacija baterije za tu aplikaciju."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"slanje upita za sve pakete"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Aplikaciji omogućuje pregled instaliranih paketa."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"pristupiti AdServices Topics API-ju"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Omogućuje aplikaciji pristupanje AdServices Topics API-ju."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"pristupiti AdServices Attribution API-jima"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Omogućuje aplikaciji pristupanje AdServices Attribution API-jima."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"pristupiti AdServices Custom Audiences API-ju"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Omogućuje aplikaciji pristupanje AdServices Custom Audiences API-ju."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Dvaput dotaknite za upravljanje zumiranjem"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Widget nije moguće dodati."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Idi"</string>
@@ -1940,6 +1934,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutačno nije dostupna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – nije dostupno"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Potrebno je dopuštenje"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Trenutačno toj aplikaciji nije moguće pristupiti na vašem uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Pokušajte joj pristupiti na Android TV uređaju."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Trenutačno toj aplikaciji nije moguće pristupiti na vašem uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Pokušajte joj pristupiti na svojem tabletu."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Trenutačno toj aplikaciji nije moguće pristupiti na vašem uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Pokušajte joj pristupiti na svojem telefonu."</string>
@@ -2035,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Želite li dopustiti aplikaciji <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> da pristupa svim zapisnicima uređaja?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Samo ovaj put"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nemoj dopustiti"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"U zapisnicima uređaja bilježi se što se događa na uređaju. Aplikacije mogu koristiti te zapisnike kako bi pronašle i riješile poteškoće.\n\nNeki zapisnici mogu sadržavati osjetljive podatke, pa pristup svim zapisnicima uređaja odobrite samo pouzdanim aplikacijama. \n\nAko ne dopustite ovoj aplikaciji da pristupa svim zapisnicima uređaja, ona i dalje može pristupati svojim zapisnicima, a proizvođač uređaja i dalje može pristupati nekim zapisnicima ili podacima na vašem uređaju. Saznajte više"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikazuj ponovo"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> želi prikazivati isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
@@ -2269,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> izvodi se u pozadini i prazni bateriju. Dodirnite za pregled."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> dugo se izvodi u pozadini. Dodirnite za pregled."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Provjera aktivnih aplikacija"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Kameri se ne može pristupiti s ovog uređaja"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Jezik sustava"</string>
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 4cefac6c1b23..f47273487e7b 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Az alkalmazás engedélyt kérhet az akkumulátoroptimalizálási beállítások mellőzésére."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"az összes csomag lekérdezése"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Engedélyezi az adott alkalmazás számára, hogy lássa az összes telepített csomagot."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"hozzáférés az AdServices Topics API-hoz"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Lehetővé teszi egy alkalmazás számára, hogy hozzáférjen az AdServices Topics API-hoz."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"hozzáférés az AdServices Attribution API-khoz"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Lehetővé teszi egy alkalmazás számára, hogy hozzáférjen az AdServices Attribution API-khoz."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"hozzáférés az AdServices Custom Audiences API-hoz"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Lehetővé teszi egy alkalmazás számára, hogy hozzáférjen az AdServices Custom Audiences API-hoz."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Érintse meg kétszer a nagyítás beállításához"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Nem sikerült hozzáadni a modult."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Ugrás"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Az alkalmazás nem hozzáférhető"</string>
<string name="app_blocked_message" msgid="542972921087873023">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> jelenleg nem hozzáférhető."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"A(z) <xliff:g id="ACTIVITY">%1$s</xliff:g> nem áll rendelkezése"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Ehhez jelenleg nem lehet hozzáférni a következő eszközön: <xliff:g id="DEVICE">%1$s</xliff:g>. Próbálja újra Android TV-eszközén."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Ehhez jelenleg nem lehet hozzáférni a következő eszközön: <xliff:g id="DEVICE">%1$s</xliff:g>. Próbálja újra a táblagépén."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Ehhez jelenleg nem lehet hozzáférni a következő eszközön: <xliff:g id="DEVICE">%1$s</xliff:g>. Próbálja újra a telefonján."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Engedélyezi a(z) <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> számára, hogy hozzáférjen az összes eszköznaplóhoz?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Csak most"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Tiltás"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Az eszköznaplók rögzítik, hogy mi történik az eszközén. Az alkalmazások ezeket a naplókat használhatják a problémák megkeresésére és kijavítására.\n\nBizonyos naplók érzékeny adatokat is tartalmazhatnak, ezért csak olyan alkalmazások számára engedélyezze az összes eszköznaplóhoz való hozzáférést, amelyekben megbízik. \n\nHa nem engedélyezi ennek az alkalmazásnak, hogy hozzáférjen az összes eszköznaplójához, az app továbbra is hozzáférhet a saját naplóihoz, és előfordulhat, hogy az eszköz gyártója továbbra is hozzáfér az eszközön található bizonyos naplókhoz és adatokhoz. További információ."</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne jelenjen meg újra"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"A(z) <xliff:g id="APP_0">%1$s</xliff:g> alkalmazás részleteket szeretne megjeleníteni a(z) <xliff:g id="APP_2">%2$s</xliff:g> alkalmazásból"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Szerkesztés"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"A(z) <xliff:g id="APP">%1$s</xliff:g> fut a háttérben, és meríti az akkumulátort. Koppintson az áttekintéshez."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"A(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazás már hosszú ideje fut a háttérben. Koppintson az áttekintéshez."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Aktív alkalmazások ellenőrzése"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Ezen az eszközön nem lehet hozzáférni a kamerához"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Alapértelmezett nyelv"</string>
</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index f1707407ba42..88a8e14c17e2 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Հավելվածին հնարավորություն է տալիս հայցելու թույլտվություն՝ տվյալ հավելվածի համար մարտկոցի օպտիմալացումն անտեսելու համար:"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"հարցում բոլոր փաթեթների համար"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Թույլ է տալիս հավելվածին տեսնել բոլոր տեղադրված փաթեթները։"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API-ի օգտագործման թույլտվություն"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Թույլ է տալիս հավելվածին օգտագործել AdServices Topics API-ը։"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API-ների օգտագործման թույլտվություն"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Թույլ է տալիս հավելվածին օգտագործել AdServices Attribution API-ները։"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API-ի օգտագործման թույլտվություն"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Թույլ է տալիս հավելվածին օգտագործել AdServices Custom Audiences API-ը։"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Հպեք երկու անգամ` խոշորացման վերահսկման համար"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Չհաջողվեց վիջեթ ավելացնել:"</string>
<string name="ime_action_go" msgid="5536744546326495436">"Առաջ"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Հավելվածը հասանելի չէ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածն այս պահին հասանելի չէ։"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>՝ անհասանելի է"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Այս պահին հնարավոր չէ բացել հավելվածը <xliff:g id="DEVICE">%1$s</xliff:g> սարքում։ Փորձեք Android TV սարքում։"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Այս պահին հնարավոր չէ բացել հավելվածը <xliff:g id="DEVICE">%1$s</xliff:g> սարքում։ Փորձեք ձեր պլանշետում։"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Այս պահին հնարավոր չէ բացել հավելվածը <xliff:g id="DEVICE">%1$s</xliff:g> սարքում։ Փորձեք ձեր հեռախոսում։"</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Հասանելի դարձնե՞լ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> հավելվածին սարքի բոլոր մատյանները"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Միայն այս անգամ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Չթույլատրել"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Այն, ինչ տեղի է ունենում ձեր սարքում, գրանցվում է սարքի մատյաններում։ Հավելվածները կարող են օգտագործել դրանք՝ անսարքությունները հայտնաբերելու և վերացնելու նպատակով։\n\nՔանի որ որոշ մատյաններ պարունակում են անձնական տեղեկություններ, խորհուրդ ենք տալիս հասանելի դարձնել ձեր սարքի բոլոր մատյանները միայն վստահելի հավելվածներին։ \n\nԵթե այս հավելվածին նման թույլտվություն չեք տվել, դրան նախկինի պես հասանելի կլինեն իր մատյանները։ Հնարավոր է՝ ձեր սարքի արտադրողին ևս հասանելի լինեն սարքի որոշ մատյաններ և տեղեկություններ։ Իմանալ ավելին"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Այլևս ցույց չտալ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> հավելվածն ուզում է ցուցադրել հատվածներ <xliff:g id="APP_2">%2$s</xliff:g> հավելվածից"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Փոփոխել"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g>-ն աշխատում է ֆոնային ռեժիմում և սպառում է մարտկոցը։ Հպեք՝ դիտելու համար։"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> հավելվածը երկար ժամանակ աշխատում է ֆոնային ռեժիմում։ Հպեք՝ դիտելու համար։"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Ստուգել ակտիվ հավելվածները"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Հնարավոր չէ բացել տեսախցիկն այս սարքից"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Համակարգի լեզու"</string>
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index a16505c5f2ea..fd9ff4de391b 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Mengizinkan aplikasi meminta izin untuk mengabaikan pengoptimalan baterai bagi aplikasi tersebut."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"mengkueri semua paket"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Mengizinkan aplikasi melihat semua paket yang diinstal."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"mengakses AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Mengizinkan aplikasi mengakses AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"mengakses AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Mengizinkan aplikasi mengakses AdServices Attribution API."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"mengakses AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Mengizinkan aplikasi mengakses AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Ketuk dua kali untuk kontrol perbesar/perkecil"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Tidak dapat menambahkan widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Buka"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikasi tidak tersedia"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia saat ini."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> tidak tersedia"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Aplikasi ini tidak dapat diakses di <xliff:g id="DEVICE">%1$s</xliff:g> untuk saat ini. Coba di perangkat Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Aplikasi ini tidak dapat diakses di <xliff:g id="DEVICE">%1$s</xliff:g> untuk saat ini. Coba di tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Aplikasi ini tidak dapat diakses di <xliff:g id="DEVICE">%1$s</xliff:g> untuk saat ini. Coba di ponsel."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Izinkan <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> mengakses semua log perangkat?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Hanya kali ini"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Jangan izinkan"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Log perangkat merekam hal-hal yang terjadi di perangkat Anda. Aplikasi dapat menggunakan log ini untuk menemukan dan memperbaiki masalah.\n\nBeberapa log mungkin berisi info sensitif, jadi hanya izinkan aplikasi yang Anda percayai untuk mengakses semua log perangkat. \n\nJika Anda tidak mengizinkan aplikasi ini mengakses semua log perangkat, aplikasi masih dapat mengakses log-nya sendiri dan produsen perangkat masih dapat mengakses beberapa log atau info di perangkat Anda. Pelajari lebih lanjut"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Jangan tampilkan lagi"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ingin menampilkan potongan <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> mengonsumsi banyak daya di latar belakang. Ketuk untuk meninjau."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> berjalan di latar belakang dalam waktu yang lama. Ketuk untuk meninjau."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Periksa aplikasi aktif"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Tidak dapat mengakses kamera dari perangkat ini"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Bahasa sistem"</string>
</resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 6b30619db15b..16af64fdc89f 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Gerir forriti kleift að biðja um heimild til að hunsa rafhlöðusparnað fyrir forritið."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"spyrja fyrir alla pakka"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Leyfir forriti að sjá alla uppsetta pakka."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"opna forritaskil umfjöllunarefna AdServices"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Veitir forritum aðgang að forritaskilum umfjöllunarefna AdServices."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"opna forritaskil eigindar AdServices"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Veitir forriti aðgang að forritaskilum eigindar AdServices."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"opna forritaskil sérsniðinna áhorfenda AdServices"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Veitir forritum aðgang að forritaskilum sérsniðinna áhorfenda AdServices."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Ýttu tvisvar til að opna aðdráttarstýringar"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Ekki tókst að bæta græju við."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Áfram"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Forrit er ekki tiltækt"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ekki tiltækt núna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ekki í boði"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Aðgangur að þessu í <xliff:g id="DEVICE">%1$s</xliff:g> er ekki í boði eins og er. Prófaðu það í Android TV tækinu í staðinn."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Aðgangur að þessu í <xliff:g id="DEVICE">%1$s</xliff:g> er ekki í boði eins og er. Prófaðu það í spjaldtölvunni í staðinn."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Aðgangur að þessu í <xliff:g id="DEVICE">%1$s</xliff:g> er ekki í boði eins og er. Prófaðu það í símanum í staðinn."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Veita <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> aðgang að öllum annálum í tækinu?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Aðeins í þetta skipti"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ekki leyfa"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Annálar tækisins skrá niður það sem gerist í tækinu. Forrit geta notað þessa annála til að finna og lagfæra vandamál.\n\nTilteknir annálar innihalda viðkvæmar upplýsingar og því skaltu einungis veita forritum sem þú treystir aðgang að öllum annálum tækisins. \n\nEf þú veitir þessu forriti ekki aðgang að öllum annálum tækisins hefur það áfram aðgang að eigin annálum og framleiðandi tækisins getur hugsanlega opnað tiltekna annála eða upplýsingar í tækinu. Nánar"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ekki sýna aftur"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vill sýna sneiðar úr <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Breyta"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> keyrir í bakgrunni og eyðir rafhlöðuorku. Ýttu til að skoða."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> hefur keyrt lengi í bakgrunni. Ýttu til að skoða."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Skoða virk forrit"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Aðgangur að myndavél er ekki tiltækur í þessu tæki"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Tungumál kerfis"</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 0394cea80653..e21c2fd21949 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Consente a un\'app di chiedere l\'autorizzazione a ignorare le ottimizzazioni della batteria per quell\'app."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"Invio di query per tutti i pacchetti"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Consente a un\'app di visualizzare tutti i pacchetti installati."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"accedi all\'API AdServices Topics"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Consente a un\'applicazione di accedere all\'API AdServices Topics."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"accedi alle API AdServices Attribution"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Consente a un\'applicazione di accedere alle API AdServices Attribution."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"accedi all\'API AdServices Custom Audiences"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Consente a un\'applicazione di accedere all\'API AdServices Custom Audiences."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Tocca due volte per il comando dello zoom"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Aggiunta del widget non riuscita."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Vai"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"L\'app non è disponibile"</string>
<string name="app_blocked_message" msgid="542972921087873023">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> non è al momento disponibile."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non disponibile"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Al momento non è possibile accedere a questa app su <xliff:g id="DEVICE">%1$s</xliff:g>. Prova a usare il dispositivo Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Al momento non è possibile accedere a questa app su <xliff:g id="DEVICE">%1$s</xliff:g>. Prova a usare il tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Al momento non è possibile accedere a questa app su <xliff:g id="DEVICE">%1$s</xliff:g>. Prova a usare il telefono."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Consentire all\'app <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> di accedere a tutti i log del dispositivo?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Solo questa volta"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Non consentire"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"I log del dispositivo registrano tutto ciò che succede sul tuo dispositivo. Le app possono usare i log per individuare problemi e correggerli.\n\nAlcuni log potrebbero contenere informazioni sensibili, quindi concedi l\'accesso ai log del dispositivo soltanto alle app attendibili. \n\nSe le neghi l\'accesso a tutti i log del dispositivo, l\'app può comunque accedere ai propri log e il produttore del tuo dispositivo potrebbe essere ancora in grado di accedere ad alcuni log o informazioni sul dispositivo. Scopri di più"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Non mostrare più"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"L\'app <xliff:g id="APP_0">%1$s</xliff:g> vuole mostrare porzioni dell\'app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Modifica"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> è in esecuzione in background e consuma batteria. Tocca per controllare."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> è in esecuzione in background da molto tempo. Tocca per controllare."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Verifica le app attive"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Impossibile accedere alla fotocamera da questo dispositivo"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Lingua di sistema"</string>
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 86468302c17f..5a8206ae01c5 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1453,12 +1453,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"מאפשרת לאפליקציה לבקש רשות להתעלם מאופטימיזציות של הסוללה לאפליקציה הזו."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"שליחת שאילתות לכל החבילות"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"מאפשרת לאפליקציה לראות את כל החבילות המותקנות."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"‏גישה לממשק ה‑API של \'נושאים\' ב‑AdServices"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"‏מאפשרת לאפליקציה לגשת לממשק ה‑API של \'נושאים\' ב‑AdServices."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"‏גישה לממשקי ה‑API של \'שיוך\' (Attribution) ב‑AdServices"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"‏מאפשרת לאפליקציה לגשת לממשקי ה‑API של \'שיוך\' (Attribution) ב‑AdServices."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"‏גישה לממשק ה‑API של \'קהלים בהתאמה אישית\' ב‑AdServices"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"‏מאפשרת לאפליקציה לגשת לממשק ה‑API של \'קהלים בהתאמה אישית\' ב‑AdServices."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"יש להקיש פעמיים לשינוי המרחק מהתצוגה"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"‏לא ניתן להוסיף widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"התחלה"</string>
@@ -1941,6 +1935,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"האפליקציה לא זמינה"</string>
<string name="app_blocked_message" msgid="542972921087873023">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא זמינה בשלב זה."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> לא זמינה"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"‏אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, יש לנסות במכשיר Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, יש לנסות בטאבלט."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, יש לנסות בטלפון."</string>
@@ -2036,7 +2032,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"לתת לאפליקציה <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> הרשאת גישה לכל יומני המכשיר?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"רק הפעם"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"אין אישור"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"ביומני המכשיר מתועדת הפעילות במכשיר. האפליקציות יכולות להשתמש ביומנים האלה כדי למצוא בעיות ולפתור אותן.\n\nהמידע בחלק מהיומנים יכול להיות רגיש, לכן יש לתת הרשאת גישה לכל יומני המכשיר רק לאפליקציות מהימנות. \n\nגם אם האפליקציה הזו לא תקבל הרשאת גישה לכל יומני המכשיר, היא תוכל לגשת ליומנים שלה, ויכול להיות שליצרן המכשיר עדיין תהיה גישה לחלק מהיומנים או למידע במכשיר שלך. מידע נוסף"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"אין להציג שוב"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> רוצה להציג חלקים מ-<xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"עריכה"</string>
@@ -2270,7 +2267,10 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"האפליקציה <xliff:g id="APP">%1$s</xliff:g> פועלת ברקע ומרוקנת את הסוללה. יש להקיש כדי לבדוק."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"האפליקציה <xliff:g id="APP">%1$s</xliff:g> פועלת ברקע במשך הרבה זמן. יש להקיש כדי לבדוק."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"כדאי לבדוק את האפליקציות הפעילות"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"לא ניתן לגשת למצלמה מהמכשיר הזה"</string>
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
+ <skip />
<!-- no translation found for system_locale_title (3978041860457277638) -->
<skip />
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index c72ff34ff267..4b15f78687da 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"電池の最適化の無視についてアプリが確認することを許可します。"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"すべてのパッケージを照会する"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"すべてのインストール済みパッケージを参照することをアプリに許可します。"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API へのアクセス"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"AdServices Topics API へのアクセスをアプリに許可します。"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API へのアクセス"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"AdServices Attribution API へのアクセスをアプリに許可します。"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API へのアクセス"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"AdServices Custom Audiences API へのアクセスをアプリに許可します。"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ダブルタップでズームします"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"ウィジェットを追加できませんでした。"</string>
<string name="ime_action_go" msgid="5536744546326495436">"移動"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"アプリの利用不可"</string>
<string name="app_blocked_message" msgid="542972921087873023">"現在 <xliff:g id="APP_NAME">%1$s</xliff:g> はご利用になれません。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>は利用できません"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"現在、<xliff:g id="DEVICE">%1$s</xliff:g> からアクセスできません。Android TV デバイスでのアクセスをお試しください。"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"現在、<xliff:g id="DEVICE">%1$s</xliff:g> からアクセスできません。タブレットでのアクセスをお試しください。"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"現在、<xliff:g id="DEVICE">%1$s</xliff:g> からアクセスできません。スマートフォンでのアクセスをお試しください。"</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> にすべてのデバイスログへのアクセスを許可しますか?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"今回のみ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"許可しない"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"デバイスのログに、このデバイスで発生したことが記録されます。アプリは問題を検出、修正するためにこれらのログを使用することができます。\n\nログによっては機密性の高い情報が含まれている可能性があるため、すべてのデバイスログへのアクセスは信頼できるアプリにのみ許可してください。\n\nすべてのデバイスログへのアクセスをこのアプリに許可しなかった場合も、このアプリはアプリ独自のログにアクセスできます。また、デバイスのメーカーもデバイスの一部のログや情報にアクセスできる可能性があります。詳細"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"次回から表示しない"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"「<xliff:g id="APP_0">%1$s</xliff:g>」が「<xliff:g id="APP_2">%2$s</xliff:g>」のスライスの表示をリクエストしています"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"編集"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> がバックグラウンドでバッテリーを消費しています。タップして確認。"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> がバックグラウンドで長時間実行されています。タップしてご確認ください。"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"有効なアプリをチェック"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"このデバイスからはカメラにアクセスできません"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"システムの言語"</string>
</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index ec80e5b08d89..6e3bfebe4a90 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"საშუალებას მისცემს აპს, მოითხოვოს მასთან დაკავშირებული ბატარეის ოპტიმიზაციის იგნორირების ნებართვა."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"ყველა პაკეტის მოთხოვნა"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"საშუალებას აძლევს აპს, ნახოს ყველა ინსტალირებული პაკეტი."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"წვდომა AdServices Topics API-ებზე"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"აპლიკაციას აძლევს წვდომას AdServices Topics API-ებზე."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"წვდომა AdServices Attribution API-ებზე"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"აპლიკაციას აძლევს წვდომას AdServices Attribution API-ებზე."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"წვდომა AdServices Custom Audiences API-ებზე"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"აპლიკაციას აძლევს წვდომას AdServices Custom Audiences API-ებზე."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"მასშტაბის ცვლილებისთვის შეეხეთ ორჯერ"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"ვერ დაემატა ვიჯეტი."</string>
<string name="ime_action_go" msgid="5536744546326495436">"გადასვლა"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"აპი მიუწვდომელია"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ამჟამად მიუწვდომელია."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> მიუწვდომელია"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ამჟამად ამ აპზე თქვენი <xliff:g id="DEVICE">%1$s</xliff:g>-დან წვდომა შეუძლებელია. ცადეთ Android TV მოწყობილობიდან."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ამჟამად ამ აპზე თქვენი <xliff:g id="DEVICE">%1$s</xliff:g>-დან წვდომა შეუძლებელია. ცადეთ ტაბლეტიდან."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ამჟამად ამ აპზე თქვენი <xliff:g id="DEVICE">%1$s</xliff:g>-დან წვდომა შეუძლებელია. ცადეთ ტელეფონიდან."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"გსურთ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>-ს მიანიჭოთ მოწყობილობის ყველა ჟურნალზე წვდომა?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"მხოლოდ ამ ერთხელ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"არ დაიშვას"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"მოწყობილობის ჟურნალში იწერება, რა ხდება ამ მოწყობილობაზე. აპებს შეუძლია ამ ჟურნალების გამოყენება პრობლემების აღმოსაჩენად და მოსაგვარებლად.\n\nზოგი ჟურნალი შეიძლება სენსიტიური ინფორმაციის მატარებელი იყოს, ამიტომაც მოწყობილობის ყველა ჟურნალზე წვდომა მხოლოდ სანდო აპებს მიანიჭეთ. \n\nთუ ამ აპს მოწყობილობის ყველა ჟურნალზე წვდომას არ მიანიჭებთ, მას მაინც ექნება წვდომა თქვენს ჟურნალებზე და თქვენი მოწყობილობის მწარმოებელს მაინც შეეძლება თქვენი მოწყობილობის ზოგიერთ ჟურნალსა თუ ინფორმაციაზე წვდომა. შეიტყვეთ მეტი"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"აღარ გამოჩნდეს"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>-ს სურს, გაჩვენოთ <xliff:g id="APP_2">%2$s</xliff:g>-ის ფრაგმენტები"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"რედაქტირება"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> გაშვებულია ფონში და იყენებს ბატარეას. შეეხეთ გადასახედად."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ფონურ რეჟიმში დიდი ხანია გაშვებულია. შეეხეთ გადასახედად."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"აქტიური აპების შემოწმება"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"კამერაზე წვდომა ამ მოწყობილობიდან ვერ მოხერხდება"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"სისტემის ენა"</string>
</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 240566459153..6a2064d46f7e 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Қолданба батареяны оңтайландыру әрекетін елемеуді сұрай алады."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"барлық бумаға сұрау жасау"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Қолданба барлық орнатылған буманы көре алады."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API-ын пайдалану"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Қолданбаға AdServices Topics API-ын пайдалануға мүмкіндік береді."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API-ларын пайдалану"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Қолданбаға AdServices Attribution API-ларын пайдалануға мүмкіндік береді."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API-ын пайдалану"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Қолданбаға AdServices Custom Audiences API-ын пайдалануға мүмкіндік береді."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Масштабтау параметрін басқару үшін екі рет түртіңіз"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Виджетті қосу."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Өту"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Қолданба қолжетімді емес"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> қазір қолжетімді емес."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> қолжетімсіз"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Қазір бұған <xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан кіру мүмкін емес. Оның орнына Android TV құрылғысын пайдаланып көріңіз."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Қазір бұған <xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан кіру мүмкін емес. Оның орнына планшетті пайдаланып көріңіз."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Қазір бұған <xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан кіру мүмкін емес. Оның орнына телефонды пайдаланып көріңіз."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> қолданбасына барлық құрылғының журналын пайдалануға рұқсат берілсін бе?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Тек осы жолы"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Рұқсат бермеу"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Журналдарға құрылғыда не болып жатқаны жазылады. Қолданбалар осы журналдарды қате тауып, түзету үшін пайдаланады.\n\nКейбір журналдарда құпия ақпарат болуы мүмкін. Сондықтан барлық құрылғының журналын пайдалану рұқсаты тек сенімді қолданбаларға берілуі керек. \n\nБұл қолданбаға барлық құрылғының журналын пайдалануға рұқсат бермесеңіз де, ол өзінің журналдарын пайдалана береді. Сондай-ақ құрылғы өндірушісі де құрылғыдағы кейбір журналдарды немесе ақпаратты пайдалануы мүмкін. Толығырақ"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Қайта көрсетілмесін"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> қолданбасы <xliff:g id="APP_2">%2$s</xliff:g> қолданбасының үзінділерін көрсеткісі келеді"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Өзгерту"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> қолданбасы фондық режимде жұмыс істеуде және батарея жұмсауда. Көру үшін түртіңіз."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> қолданбасы ұзақ уақыт бойы фондық режимде жұмыс істеуде. Көру үшін түртіңіз."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Белсенді қолданбаларды тексеру"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Бұл құрылғыдан камераны пайдалану мүмкін емес."</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Жүйе тілі"</string>
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 772205f05896..a8225c3d4e41 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"អនុញ្ញាតឲ្យកម្មវិធីស្នើសុំការអនុញ្ញាត ដើម្បីមិនអើពើចំពោះការបង្កើនប្រសិទ្ធភាពថ្ម។"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"សួរសំណួរអំពីកញ្ចប់ទាំងអស់"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"អនុញ្ញាតឱ្យកម្មវិធីមើលកញ្ចប់ដែលបានដំឡើងទាំងអស់។"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"ចូលប្រើ AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"អនុញ្ញាតឱ្យកម្មវិធីចូលប្រើ AdServices Topics API។"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"ចូលប្រើ AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"អនុញ្ញាតឱ្យកម្មវិធីចូលប្រើ AdServices Attribution API។"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"ចូលប្រើ AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"អនុញ្ញាតឱ្យកម្មវិធីចូលប្រើ AdServices Custom Audiences API។"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ប៉ះ ពីរ​ដង​ដើម្បី​ពិនិត្យ​ការ​ពង្រីក"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"មិន​អាច​បន្ថែម​ធាតុ​ក្រាហ្វិក។"</string>
<string name="ime_action_go" msgid="5536744546326495436">"ទៅ"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"មិនអាច​ប្រើ​កម្មវិធី​នេះបានទេ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"មិនអាច​ប្រើ <xliff:g id="APP_NAME">%1$s</xliff:g> នៅពេល​នេះ​បានទេ​។"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"មិនអាចប្រើ <xliff:g id="ACTIVITY">%1$s</xliff:g> បានទេ"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"មិនអាចប្រើ​កម្មវិធីនេះ​នៅលើ <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នក​នៅពេលនេះ​បានទេ។ សូមសាកល្បងប្រើ​នៅលើ​ឧបករណ៍ Android TV របស់អ្នក​ជំនួសវិញ។"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"មិនអាចប្រើ​កម្មវិធីនេះ​នៅលើ <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នក​នៅពេលនេះ​បានទេ។ សូមសាកល្បងប្រើ​នៅលើ​ថេប្លេត​របស់អ្នក​ជំនួសវិញ។"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"មិនអាចប្រើ​កម្មវិធីនេះ​នៅលើ <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នក​នៅពេលនេះ​បានទេ។ សូមសាកល្បងប្រើ​នៅលើ​ទូរសព្ទរបស់អ្នក​ជំនួសវិញ។"</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"អនុញ្ញាតឱ្យ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ចូលប្រើកំណត់ហេតុឧបករណ៍ទាំងអស់ឬ?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"តែពេលនេះ​ប៉ុណ្ណោះ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"មិនអនុញ្ញាត"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"កំណត់ហេតុឧបករណ៍កត់ត្រាអ្វីដែលកើតឡើងនៅលើឧបករណ៍របស់អ្នក។ កម្មវិធីអាចប្រើកំណត់ហេតុទាំងនេះដើម្បីស្វែងរក និងដោះស្រាយបញ្ហាបាន។\n\nកំណត់ហេតុមួយចំនួនអាចមានព័ត៌មានរសើប ដូច្នេះគួរអនុញ្ញាតឱ្យចូលប្រើកំណត់ហេតុឧបករណ៍ទាំងអស់សម្រាប់តែកម្មវិធីដែលអ្នកទុកចិត្តប៉ុណ្ណោះ។ \n\nប្រសិនបើអ្នកមិនអនុញ្ញាតឱ្យកម្មវិធីនេះចូលប្រើកំណត់ហេតុឧបករណ៍ទាំងអស់ទេ វានៅតែអាចចូលប្រើកំណត់ហេតុរបស់វាផ្ទាល់ ហើយក្រុមហ៊ុនផលិតឧបករណ៍របស់អ្នកប្រហែលជានៅតែអាចចូលប្រើកំណត់ហេតុ ឬព័ត៌មានមួយចំនួននៅលើឧបករណ៍របស់អ្នកបានដដែល។ ស្វែងយល់បន្ថែម"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"កុំ​បង្ហាញ​ម្ដង​ទៀត"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ចង់​បង្ហាញ​ស្ថិតិ​ប្រើប្រាស់​របស់ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"កែសម្រួល"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> កំពុងដំណើរការនៅផ្ទៃខាងក្រោយ និងធ្វើឱ្យអស់ថ្មលឿន។ សូមចុច ដើម្បី​ពិនិត្យមើល។"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> កំពុងដំណើរការនៅផ្ទៃខាងក្រោយអស់រយៈពេលយូរហើយ។ សូមចុច ដើម្បី​ពិនិត្យមើល។"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ពិនិត្យមើលកម្មវិធីសកម្ម"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"មិនអាចចូលប្រើកាមេរ៉ាពីឧបករណ៍នេះបានទេ"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"ភាសាប្រព័ន្ធ"</string>
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 022d665f7d3f..b9e17b60de67 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"ಈ ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಬ್ಯಾಟರಿ ಆಪ್ಟಿಮೈಸೇಶನ್‌ಗಳನ್ನು ಕಡೆಗಣಿಸುವುದಕ್ಕೆ ಅನುಮತಿಯನ್ನು ಕೇಳಲು ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"ಎಲ್ಲಾ ಪ್ಯಾಕೇಜ್‌ಗಳ ಕುರಿತಾದ ಮಾಹಿತಿಯನ್ನು ಕೇಳಿ"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿದ ಎಲ್ಲಾ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API ಅನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"AdServices Topics API ಅನ್ನು ಪ್ರವೇಶಿಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution APIs ಅನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"AdServices Attribution APIs ಅನ್ನು ಪ್ರವೇಶಿಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API ಅನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"AdServices Custom Audiences API ಅನ್ನು ಪ್ರವೇಶಿಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ಝೂಮ್‌ ನಿಯಂತ್ರಿಸಲು ಎರಡು ಬಾರಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"ವಿಜೆಟ್ ಸೇರಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ."</string>
<string name="ime_action_go" msgid="5536744546326495436">"ಹೋಗು"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ಆ್ಯಪ್ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಇದೀಗ ಲಭ್ಯವಿಲ್ಲ."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ಲಭ್ಯವಿಲ್ಲ"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"ಅನುಮತಿಯ ಅಗತ್ಯವಿದೆ"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ಈ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ನಲ್ಲಿ ಇದನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅದರ ಬದಲು ನಿಮ್ಮ Android TV ಸಾಧನದಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ಈ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ನಲ್ಲಿ ಇದನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅದರ ಬದಲು ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್‌ನಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ಈ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ನಲ್ಲಿ ಇದನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅದರ ಬದಲು ನಿಮ್ಮ ಫೋನ್‌ನಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"ಎಲ್ಲಾ ಸಾಧನದ ಲಾಗ್‌ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ಗೆ ಅನುಮತಿಸುವುದೇ?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"ಈ ಬಾರಿ ಮಾತ್ರ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"ಅನುಮತಿಸಬೇಡಿ"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"ಸಾಧನವು ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಲಾಗ್ ಮಾಡುತ್ತದೆ ಸಮಸ್ಯೆಗಳನ್ನು ಪತ್ತೆಹಚ್ಚಲು ಮತ್ತು ಪರಿಹರಿಸಲು ಆ್ಯಪ್‌ಗಳು ಈ ಲಾಗ್ ಅನ್ನು ಬಳಸಬಹುದು.\n\nಕೆಲವು ಲಾಗ್‌ಗಳು ಸೂಕ್ಷ್ಮ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಿರಬಹುದು, ಆದ್ದರಿಂದ ನಿಮ್ಮ ವಿಶ್ವಾಸಾರ್ಹ ಆ್ಯಪ್‌ಗಳಿಗೆ ಮಾತ್ರ ಸಾಧನದ ಎಲ್ಲಾ ಲಾಗ್‌ಗಳಿಗೆ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಅನುಮತಿಸಿ. \n\nಎಲ್ಲಾ ಸಾಧನ ಲಾಗ್‌ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ನೀವು ಈ ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸದಿದ್ದರೆ, ಅದು ಇನ್ನೂ ತನ್ನದೇ ಆದ ಲಾಗ್‌ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಬಹುದು ಮತ್ತು ನಿಮ್ಮ ಸಾಧನ ತಯಾರಕರು ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಕೆಲವು ಲಾಗ್‌ಗಳು ಅಥವಾ ಮಾಹಿತಿಯನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ಈಗಲೂ ಸಾಧ್ಯವಾಗುತ್ತದೆ. ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸಬೇಡಿ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_2">%2$s</xliff:g> ಸ್ಲೈಸ್‌ಗಳನ್ನು <xliff:g id="APP_0">%1$s</xliff:g> ತೋರಿಸಲು ಬಯಸಿದೆ"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ಎಡಿಟ್"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ಹಿನ್ನೆಲೆಯಲ್ಲಿ ರನ್ ಆಗುತ್ತಿದ್ದು ಬ್ಯಾಟರಿ ಖಾಲಿ ಮಾಡುತ್ತಿದೆ. ಪರಿಶೀಲಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ಬಹಳ ಸಮಯದಿಂದ ಹಿನ್ನೆಲೆಯಲ್ಲಿ ರನ್ ಆಗುತ್ತಿದೆ. ಪರಿಶೀಲಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ಸಕ್ರಿಯ ಆ್ಯಪ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"ಈ ಸಾಧನದಿಂದ ಕ್ಯಾಮರಾ ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"ಸಿಸ್ಟಂ ಭಾಷೆ"</string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 914e9c96c70b..1b657b661c9b 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"앱에서 배터리 최적화를 무시할 수 있는 권한을 요청할 수 있도록 허용합니다."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"모든 패키지 쿼리"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"앱이 설치된 패키지를 모두 볼 수 있도록 허용합니다."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API 액세스"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"애플리케이션이 AdServices Topics API에 액세스하도록 허용합니다."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API 액세스"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"애플리케이션이 AdServices Attribution API에 액세스하도록 허용합니다."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API 액세스"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"애플리케이션이 AdServices Custom Audiences API에 액세스하도록 허용합니다."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"확대/축소하려면 두 번 탭하세요."</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"위젯을 추가할 수 없습니다."</string>
<string name="ime_action_go" msgid="5536744546326495436">"이동"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"앱을 사용할 수 없습니다"</string>
<string name="app_blocked_message" msgid="542972921087873023">"현재 <xliff:g id="APP_NAME">%1$s</xliff:g> 앱을 사용할 수 없습니다."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 사용할 수 없음"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"현재 <xliff:g id="DEVICE">%1$s</xliff:g>에서 액세스할 수 없습니다. 대신 Android TV 기기에서 시도해 보세요."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"현재 <xliff:g id="DEVICE">%1$s</xliff:g>에서 액세스할 수 없습니다. 대신 태블릿에서 시도해 보세요."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"현재 <xliff:g id="DEVICE">%1$s</xliff:g>에서 액세스할 수 없습니다. 대신 스마트폰에서 시도해 보세요."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>에서 모든 기기에 액세스하도록 허용하시겠습니까?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"이번만 허용"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"허용 안함"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"기기 로그에 기기에서 발생한 상황이 기록됩니다. 앱은 문제를 찾고 해결하는 데 이 로그를 사용할 수 있습니다.\n\n일부 로그에는 민감한 정보가 포함될 수 있으므로 신뢰할 수 있는 앱만 전체 기기 로그에 액세스하도록 허용하세요. \n\n앱에 전체 기기 로그에 대한 액세스 권한을 부여하지 않아도 앱이 자체 로그에는 액세스할 수 있으며, 기기 제조업체에서 일부 로그 또는 기기 내 정보에 액세스할 수 있습니다. 자세히 알아보기"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"다시 표시 안함"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>에서 <xliff:g id="APP_2">%2$s</xliff:g>의 슬라이스를 표시하려고 합니다"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"수정"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> 앱이 백그라운드에서 실행 중이며 배터리를 소모하고 있습니다. 확인하려면 탭하세요."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> 앱이 백그라운드에서 오랫동안 실행 중입니다. 확인하려면 탭하세요."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"활성 상태의 앱 확인"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"이 기기에서 카메라에 액세스할 수 없습니다."</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"시스템 언어"</string>
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index c781be2708e6..5983ddfb8cd2 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Колдонмо батареянын кубатын керектегенден мурун уруксат суралсын."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"бардык топтомдор боюнча сурам жөнөтүү"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Колдонмо бардык орнотулган топтомдорду көрөт."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API\'син колдонуу мүмкүнчүлүгү"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Колдонмого AdServices Topics API\'син колдонууга мүмкүнчүлүк берет."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API\'лерин колдонуу мүмкүнчүлүгү"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Колдонмого AdServices Attribution API\'лерин колдонууга мүмкүнчүлүк берет."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API\'син колдонуу мүмкүнчүлүгү"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Колдонмого AdServices Custom Audiences API\'син колдонууга мүмкүнчүлүк берет."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Масштабдын параметрлерин өзгөртүү үчүн бул жерди эки жолу басыңыз."</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Виджетти кошуу мүмкүн болбоду."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Өтүү"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Колдонмо учурда жеткиликсиз"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> учурда жеткиликсиз"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> жеткиликсиз"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Учурда буга <xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүңүздөн кире албайсыз. Android TV түзмөгүңүздөн аракет кылып көрүңүз."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Учурда буга <xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүңүздөн кире албайсыз. Планшетиңизден кирип көрүңүз."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Учурда буга <xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүңүздөн кире албайсыз. Анын ордуна телефондон кирип көрүңүз."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> колдонмосуна түзмөктөгү бардык таржымалдарды колдонууга уруксат бересизби?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Ушул жолу гана"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Уруксат берилбесин"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Түзмөктө аткарылган бардык аракеттер түзмөктүн таржымалдарында сакталып калат. Колдонмолор бул таржымалдарды колдонуп, маселелерди оңдошот.\n\nАйрым таржымалдарда купуя маалымат болушу мүмкүн, андыктан түзмөктөгү бардык таржымалдарды ишенимдүү колдонмолорго гана пайдаланууга уруксат бериңиз. \n\nЭгер бул колдонмого түзмөктөгү айрым таржымалдарга кирүүгө тыюу салсаңыз, ал өзүнүн таржымалдарын пайдалана берет. Ал эми түзмөктү өндүрүүчү түзмөгүңүздөгү айрым таржымалдарды же маалыматты көрө берет. Кененирээк"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Экинчи көрүнбөсүн"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> колдонмосу <xliff:g id="APP_2">%2$s</xliff:g> үлгүлөрүн көрсөткөнү жатат"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Түзөтүү"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> фондо иштеп, батареяны отургузуп жатат. Көрүү үчүн таптап коюңуз."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу көп убакыттан бери фондо иштеп жатат. Көрүү үчүн таптап коюңуз."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Жигердүү колдонмолорду карап чыгуу"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Бул түзмөктөгү камераны колдонууга болбойт"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Тутумдун тили"</string>
</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index a5879e11e2b0..6ed5f1c5625a 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"ອະນຸຍາດໃຫ້ແອັບຖາມສິດອະນຸຍາດເພື່ອເພີກເສີຍຕໍ່ການປັບແຕ່ງແບັດເຕີຣີສຳລັບແອັບນັ້ນ."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"ຊອກຫາແພັກເກດທັງໝົດ"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"ອະນຸຍາດໃຫ້ແອັບເບິ່ງເຫັນແພັກເກດທີ່ຕິດຕັ້ງແລ້ວທັງໝົດໄດ້."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"ເຂົ້າເຖິງ AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນເຂົ້າເຖິງ AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"ເຂົ້າເຖິງ AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນເຂົ້າເຖິງ AdServices Attribution API."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"ເຂົ້າເຖິງ AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນເຂົ້າເຖິງ AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ແຕະສອງເທື່ອເພື່ອຄວບຄຸມການຊູມ"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"ບໍ່ສາມາດເພີ່ມວິດເຈັດໄດ້."</string>
<string name="ime_action_go" msgid="5536744546326495436">"ໄປ"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ແອັບບໍ່ສາມາດໃຊ້ໄດ້"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ສາມາດໃຊ້ໄດ້ໃນຕອນນີ້."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"ບໍ່ສາມາດໃຊ້ <xliff:g id="ACTIVITY">%1$s</xliff:g> ໄດ້"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ບໍ່ສາມາດເຂົ້າເຖິງແອັບນີ້ໄດ້ຢູ່ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໃນຕອນນີ້. ກະລຸນາລອງໃຊ້ຢູ່ອຸປະກອນ Android TV ຂອງທ່ານແທນ."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ບໍ່ສາມາດເຂົ້າເຖິງແອັບນີ້ໄດ້ຢູ່ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໃນຕອນນີ້. ກະລຸນາລອງຢູ່ແທັບເລັດຂອງທ່ານແທນ."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ບໍ່ສາມາດເຂົ້າເຖິງແອັບນີ້ໄດ້ຢູ່ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໃນຕອນນີ້. ກະລຸນາລອງຢູ່ໂທລະສັບຂອງທ່ານແທນ."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"ອະນຸຍາດໃຫ້ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດບໍ?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"ສະເພາະເທື່ອນີ້"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"ບໍ່ອະນຸຍາດ"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"ບັນທຶກອຸປະກອນຈະບັນທຶກສິ່ງທີ່ເກີດຂຶ້ນຢູ່ອຸປະກອນຂອງທ່ານ. ແອັບສາມາດໃຊ້ບັນທຶກເຫຼົ່ານີ້ເພື່ອຊອກຫາ ແລະ ແກ້ໄຂບັນຫາໄດ້.\n\nບັນທຶກບາງຢ່າງອາດມີຂໍ້ມູນລະອຽດອ່ອນ, ດັ່ງນັ້ນໃຫ້ອະນຸຍາດສະເພາະແອັບທີ່ທ່ານເຊື່ອຖືໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດເທົ່ານັ້ນ. \n\nຫາກທ່ານບໍ່ອະນຸຍາດແອັບນີ້ໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດ, ມັນຈະຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກຂອງຕົວມັນເອງໄດ້ຢູ່ ແລະ ຜູ້ຜະລິດອຸປະກອນຂອງທ່ານອາດຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກ ຫຼື ຂໍ້ມູນບາງຢ່າງຢູ່ອຸປະກອນຂອງທ່ານໄດ້. ສຶກສາເພີ່ມເຕີມ"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"ບໍ່ຕ້ອງສະແດງອີກ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ຕ້ອງການສະແດງ <xliff:g id="APP_2">%2$s</xliff:g> ສະໄລ້"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ແກ້ໄຂ"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ກຳລັງເຮັດວຽກໃນພື້ນຫຼັງ ແລະ ໃຊ້ແບັດເຕີຣີຫຼາຍ. ແຕະເພື່ອກວດສອບ."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ກຳລັງເຮັດວຽກໃນພື້ນຫຼັງເປັນເວລາດົນແລ້ວ. ແຕະເພື່ອກວດສອບ."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ກວດສອບແອັບທີ່ເຄື່ອນໄຫວ"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"ບໍ່ສາມາດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບຈາກອຸປະກອນນີ້ໄດ້"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"ພາສາລະບົບ"</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index f3cde46d165b..00089d4fe126 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1453,12 +1453,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Programai leidžiama prašyti leidimo nepaisyti tai programai skirto akumuliatoriaus optimizavimo nustatymų."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"Teikti visų paketų užklausą"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Programai leidžiama peržiūrėti visus įdiegtus paketus."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"pasiekti „AdServices Topics“ API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Leidžiama programai pasiekti „AdServices Topics“ API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"pasiekti „AdServices Attribution“ API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Leidžiama programai pasiekti „AdServices Attribution“ API."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"pasiekti „AdServices Custom Audiences“ API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Leidžiama programai pasiekti „AdServices Custom Audiences“ API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Bakstelėkite du kartus, kad valdytumėte mastelio keitimą"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Nepavyko pridėti."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Pradėti"</string>
@@ -1941,6 +1935,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Programa nepasiekiama."</string>
<string name="app_blocked_message" msgid="542972921087873023">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ šiuo metu nepasiekiama."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"„<xliff:g id="ACTIVITY">%1$s</xliff:g>“ nepasiekiama"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Šįkart nepavyksta pasiekti programos iš jūsų „<xliff:g id="DEVICE">%1$s</xliff:g>“. Pabandykite naudoti „Android TV“ įrenginį."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Šįkart nepavyksta pasiekti programos iš jūsų „<xliff:g id="DEVICE">%1$s</xliff:g>“. Pabandykite naudoti planšetinį kompiuterį."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Šįkart nepavyksta pasiekti programos iš jūsų „<xliff:g id="DEVICE">%1$s</xliff:g>“. Pabandykite naudoti telefoną."</string>
@@ -2036,7 +2032,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Leisti „<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>“ pasiekti visus įrenginio žurnalus?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Tik šį kartą"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Neleisti"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Įrenginyje įrašoma, kas įvyksta jūsų įrenginyje. Programos gali naudoti šiuos žurnalus, kad surastų ir išspręstų problemas.\n\nKai kuriuose žurnaluose gali būti neskelbtinos informacijos, todėl visus įrenginio žurnalus leiskite pasiekti tik programoms, kuriomis pasitikite. \n\nJei neleisite šiai programai pasiekti visų įrenginio žurnalų, ji vis tiek galės pasiekti savo žurnalus, o įrenginio gamintojui vis tiek gali būti leidžiama pasiekti tam tikrus žurnalus ar informaciją jūsų įrenginyje. Sužinokite daugiau"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Daugiau neberodyti"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"„<xliff:g id="APP_0">%1$s</xliff:g>“ nori rodyti „<xliff:g id="APP_2">%2$s</xliff:g>“ fragmentus"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Redaguoti"</string>
@@ -2270,7 +2267,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"„<xliff:g id="APP">%1$s</xliff:g>“ veikia fone ir eikvoja akumuliatoriaus energiją. Palieskite ir peržiūrėkite."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"„<xliff:g id="APP">%1$s</xliff:g>“ ilgą laiką veikia fone. Palieskite ir peržiūrėkite."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Peržiūrėkite aktyvias programas"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Nepavyksta pasiekti fotoaparato iš šio įrenginio"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Sistemos kalba"</string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 16b709823e0b..db66cea86007 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1452,12 +1452,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Ļauj lietotnei lūgt atļauju ignorēt akumulatora optimizāciju šai lietotnei."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"pieprasīt atļauju skatīt visas pakotnes"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Ļauj lietotnei skatīt visas instalētās pakotnes."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"Piekļuve saskarnei AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Ļauj lietojumprogrammai piekļūt saskarnei AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"Piekļuve AdServices Attribution API saskarnēm"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Ļauj lietojumprogrammai piekļūt AdServices Attribution API saskarnēm."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"Piekļuve saskarnei AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Ļauj lietojumprogrammai piekļūt saskarnei AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Pieskarieties divreiz, lai kontrolētu tālummaiņu."</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Nevarēja pievienot logrīku."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Doties uz"</string>
@@ -1940,6 +1934,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Lietotne nav pieejama"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pašlaik nav pieejama."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nav pieejams"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Šajā ierīcē (<xliff:g id="DEVICE">%1$s</xliff:g>) pašlaik nevar piekļūt šai lietotnei. Mēģiniet tai piekļūt savā Android TV ierīcē."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Šajā ierīcē (<xliff:g id="DEVICE">%1$s</xliff:g>) pašlaik nevar piekļūt šai lietotnei. Mēģiniet tai piekļūt savā planšetdatorā."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Šajā ierīcē (<xliff:g id="DEVICE">%1$s</xliff:g>) pašlaik nevar piekļūt šai lietotnei. Mēģiniet tai piekļūt savā tālrunī."</string>
@@ -2035,7 +2031,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Vai atļaujat lietotnei <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> piekļūt visiem ierīces žurnāliem?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Tikai šoreiz"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Neatļaut"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Ierīces žurnālos tiek reģistrēti ierīces procesi un notikumi. Lietotņu izstrādātāji var izmantot šos žurnālus, lai atrastu un izlabotu problēmas savās lietotnēs.\n\nDažos žurnālos var būt ietverta sensitīva informācija, tāpēc atļaujiet tikai uzticamām lietotnēm piekļūt visiem ierīces žurnāliem. \n\nJa neatļausiet šai lietotnei piekļūt visiem ierīces žurnāliem, lietotnes izstrādātājs tik un tā varēs piekļūt pašas lietotnes žurnāliem, savukārt ierīces ražotājs varbūt tik un tā varēs piekļūt noteiktiem žurnāliem vai informācijai jūsu ierīcē. Uzzināt vairāk"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Vairs nerādīt"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Lietotne <xliff:g id="APP_0">%1$s</xliff:g> vēlas rādīt lietotnes <xliff:g id="APP_2">%2$s</xliff:g> sadaļas"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Rediģēt"</string>
@@ -2269,7 +2266,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> darbojas fonā un patērē akumulatora enerģiju. Pieskarieties, lai to pārskatītu."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ilgi darbojas fonā. Pieskarieties, lai to pārskatītu."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Pārbaudiet aktīvās lietotnes"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Nevar piekļūt kamerai no šīs ierīces"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Sistēmas valoda"</string>
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 9085e6e7ce01..77532be1c1aa 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Овозможува апликацијата да побара дозвола за игнорирање на оптимизациите на батеријата за таа апликација."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"пребарување на сите пакети"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Дозволува апликацијата да ги гледа сите инсталирани пакети."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"да пристапува до AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Дозволува апликацијата да пристапува до AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"да пристапува до AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Дозволува апликацијата да пристапува до AdServices Attribution API."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"да пристапува до AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Дозволува апликацијата да пристапува до AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Допрете двапати за контрола на зумот"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Не може да се додаде виџет."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Оди"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Апликацијата не е достапна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> не е достапна во моментов."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> е недостапна"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Потребна е дозвола"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Ова не може да се отвори на <xliff:g id="DEVICE">%1$s</xliff:g> во моментов. Пробајте на вашиот Android TV како алтернатива."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Ова не може да се отвори на <xliff:g id="DEVICE">%1$s</xliff:g> во моментов. Пробајте на вашиот таблет како алтернатива."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Ова не може да се отвори на <xliff:g id="DEVICE">%1$s</xliff:g> во моментов. Пробајте на вашиот телефон како алтернатива."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Да се дозволи <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> да пристапува до целата евиденција на уредот?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Само овој пат"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дозволувај"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Дневниците за евиденција на уредот снимаат што се случува на вашиот уред. Апликациите може да ги користат овие дневници за евиденција за да наоѓаат и поправаат проблеми.\n\nНекои дневници за евиденција може да содржат чувствителни податоци, па затоа дозволете им пристап до сите дневници за евиденција на уредот само на апликациите во кои имате доверба. \n\nАко не ѝ дозволите на апликацијава да пристапува до сите дневници за евиденција на уредот, таа сепак ќе може да пристапува до сопствените дневници за евиденција, а производителот на вашиот уред можеби сепак ќе може да пристапува до некои дневници за евиденција или податоци на уредот. Дознајте повеќе"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Не прикажувај повторно"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> сака да прикажува делови од <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Измени"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> работи во заднина и ја троши батеријата. Допрете за да прегледате."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> работи во заднина веќе долго време. Допрете за да прегледате."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Проверете ги активните апликации"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Не може да се пристапи до камерата од уредов"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Јазик на системот"</string>
</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 403fbc1731c5..ab701d387e34 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"ആപ്പിന് വേണ്ടിയുള്ള ബാറ്ററി ഒപ്റ്റിമൈസേഷനുകളെ അവഗണിക്കാനുള്ള അനുമതി ചോദിക്കുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"എല്ലാ പാക്കേജുകളും നോക്കുക"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"ഇൻസ്‌റ്റാൾ ചെയ്‌ത എല്ലാ പാക്കേജുകളും കാണാൻ ഒരു ആപ്പിനെ അനുവദിക്കുന്നു."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API ആക്‌സസ് ചെയ്യൂ"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"AdServices Topics API ആക്‌സസ് ചെയ്യാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API-കൾ ആക്‌സസ് ചെയ്യൂ"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"AdServices Attribution API-കൾ ആക്‌സസ് ചെയ്യാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API ആക്‌സസ് ചെയ്യൂ"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"AdServices Custom Audiences API ആക്‌സസ് ചെയ്യാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"സൂം നിയന്ത്രണം ലഭിക്കാൻ രണ്ടുതവണ ടാപ്പുചെയ്യുക"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"വിജറ്റ് ചേർക്കാനായില്ല."</string>
<string name="ime_action_go" msgid="5536744546326495436">"പോവുക"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ആപ്പ് ലഭ്യമല്ല"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ഇപ്പോൾ ലഭ്യമല്ല."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ലഭ്യമല്ല"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"അനുമതി ആവശ്യമാണ്"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ഇപ്പോൾ നിങ്ങളുടെ <xliff:g id="DEVICE">%1$s</xliff:g> ഉപകരണത്തിൽ ഇത് ആക്‌സസ് ചെയ്യാനാകില്ല. പകരം Android TV ഉപകരണത്തിൽ ശ്രമിച്ച് നോക്കൂ."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ഇപ്പോൾ നിങ്ങളുടെ <xliff:g id="DEVICE">%1$s</xliff:g> ഉപകരണത്തിൽ ഇത് ആക്‌സസ് ചെയ്യാനാകില്ല. പകരം നിങ്ങളുടെ ടാബ്‌ലെറ്റിൽ ശ്രമിച്ച് നോക്കൂ."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ഇപ്പോൾ നിങ്ങളുടെ <xliff:g id="DEVICE">%1$s</xliff:g> ഉപകരണത്തിൽ ഇത് ആക്‌സസ് ചെയ്യാനാകില്ല. പകരം നിങ്ങളുടെ ഫോണിൽ ശ്രമിച്ച് നോക്കൂ."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"എല്ലാ ഉപകരണ ലോഗുകളും ആക്‌സസ് ചെയ്യാൻ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> എന്നതിനെ അനുവദിക്കണോ?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"ഇപ്രാവശ്യം മാത്രം"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"അനുവദിക്കരുത്"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"നിങ്ങളുടെ ഉപകരണത്തിൽ എന്തൊക്കെയാണ് സംഭവിക്കുന്നതെന്ന് ഉപകരണ ലോഗുകൾ റെക്കോർഡ് ചെയ്യുന്നു. പ്രശ്‌നങ്ങൾ കണ്ടെത്തി പരിഹരിക്കുന്നതിന് ആപ്പുകൾക്ക് ഈ ലോഗുകൾ ഉപയോഗിക്കാൻ കഴിയും.\n\nചില ലോഗുകളിൽ സൂക്ഷ്‌മമായി കൈകാര്യം ചെയ്യേണ്ട വിവരങ്ങൾ അടങ്ങിയിരിക്കാൻ സാധ്യതയുള്ളതിനാൽ, നിങ്ങൾക്ക് വിശ്വാസമുള്ള ആപ്പുകളെ മാത്രം എല്ലാ ഉപകരണ ലോഗുകളും ആക്‌സസ് ചെയ്യാൻ അനുവദിക്കുക. \n\nഎല്ലാ ഉപകരണ ലോഗുകളും ആക്‌സസ് ചെയ്യാൻ നിങ്ങൾ ഈ ആപ്പിനെ അനുവദിക്കുന്നില്ലെങ്കിൽ പോലും ആപ്പിന് അതിന്റെ സ്വന്തം ലോഗുകൾ ആക്‌സസ് ചെയ്യാനാകും, നിങ്ങളുടെ ഉപകരണ നിർമ്മാതാവിന് ഉപകരണത്തിലെ ചില ലോഗുകളോ വിവരങ്ങളോ തുടർന്നും ആക്‌സസ് ചെയ്യാനായേക്കും. കൂടുതലറിയുക"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"വീണ്ടും കാണിക്കരുത്"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_2">%2$s</xliff:g> സ്ലൈസുകൾ കാണിക്കാൻ <xliff:g id="APP_0">%1$s</xliff:g> താൽപ്പര്യപ്പെടുന്നു"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"എഡിറ്റ് ചെയ്യുക"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ആപ്പ് പശ്ചാത്തലത്തിൽ റൺ ചെയ്യുന്നു, ഇത് ബാറ്ററി ഉപയോഗിച്ചുതീർക്കുന്നു. അവലോകനം ചെയ്യാൻ ടാപ്പ് ചെയ്യുക."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"പശ്ചാത്തലത്തിൽ <xliff:g id="APP">%1$s</xliff:g> ആപ്പ് ഒരുപാട് നേരമായി റൺ ചെയ്യുന്നു. അവലോകനം ചെയ്യാൻ ടാപ്പ് ചെയ്യുക."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"സജീവമായ ആപ്പുകൾ പരിശോധിക്കുക"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"ഈ ഉപകരണത്തിൽ നിന്ന് ക്യാമറ ആക്‌സസ് ചെയ്യാനാകില്ല"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"സിസ്റ്റത്തിന്റെ ഭാഷ"</string>
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index cb7bcaf0eb8a..4e382370df4e 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Тухайн аппaaс батерейны оновчлол алгасах зөвшөөрөл асуухыг зөвшөөрдөг."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"бүх багцыг лавлах"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Аппап бүх суулгасан багцыг харахыг зөвшөөрнө."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API-д хандах"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Аппликэйшнд AdServices Topics API-д хандах зөвшөөрөл олгодог."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API-д хандах"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Аппликэйшнд AdServices Attribution API-д хандах зөвшөөрөл олгодог."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API-д хандах"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Аппликэйшнд AdServices Custom Audiences API-д хандах зөвшөөрөл олгодог."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Өсгөх контрол дээр хоёр удаа товшино уу"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Виджет нэмж чадсангүй."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Очих"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Апп боломжгүй байна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> яг одоо боломжгүй байна."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> боломжгүй байна"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Зөвшөөрөл шаардлагатай"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Одоогоор үүнд таны <xliff:g id="DEVICE">%1$s</xliff:g> дээрээс хандах боломжгүй. Оронд нь Android TV төхөөрөмж дээрээ туршиж үзнэ үү."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Одоогоор үүнд таны <xliff:g id="DEVICE">%1$s</xliff:g> дээрээс хандах боломжгүй. Оронд нь таблет дээрээ туршиж үзнэ үү."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Одоогоор үүнд таны <xliff:g id="DEVICE">%1$s</xliff:g> дээрээс хандах боломжгүй. Оронд нь утсан дээрээ туршиж үзнэ үү."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>-д төхөөрөмжийн бүх логт хандахыг зөвшөөрөх үү?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Зөвхөн энэ удаа"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Бүү зөвшөөр"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Төхөөрөмжийн лог нь таны төхөөрөмж дээр юу болж байгааг бичдэг. Аппууд эдгээр логийг асуудлыг олох болон засахад ашиглах боломжтой.\n\nЗарим лог эмзэг мэдээлэл агуулж байж магадгүй тул та зөвхөн итгэдэг аппууддаа төхөөрөмжийн бүх логт хандахыг зөвшөөрнө үү. \n\nХэрэв та энэ аппад төхөөрөмжийн бүх логт хандахыг зөвшөөрөхгүй бол энэ нь өөрийн логт хандах боломжтой хэвээр байх бөгөөд таны төхөөрөмж үйлдвэрлэгч таны төхөөрөмж дээрх зарим лог эсвэл мэдээлэлд хандах боломжтой хэвээр байж магадгүй. Нэмэлт мэдээлэл авах"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Дахиж бүү харуул"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g>-н хэсгүүдийг (slices) харуулах хүсэлтэй байна"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Засах"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> дэвсгэрт ажиллаж байгаа бөгөөд батарейг дуусгаж байна. Хянахын тулд товшино уу."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> дэвсгэрт удаан хугацааны турш ажиллаж байна. Хянахын тулд товшино уу."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Идэвхтэй аппуудыг шалгах"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Энэ төхөөрөмжөөс камер луу нэвтрэх боломжгүй байна"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Системийн хэл"</string>
</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 0580e4a27ff1..e0aa948bda16 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"त्या ॲपसाठी बॅटरी ऑप्टिमायझेशन दुर्लक्षित करण्‍यासाठी ॲपला परवानगी मागण्याची अनुमती देते."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"सर्व पॅकेजविषयी क्वेरी करा"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"ॲपला इंस्टॉल केलेले सर्व पॅकेज पाहण्याची अनुमती देते."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API अ‍ॅक्सेस करा"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"अ‍ॅप्लिकेशनला AdServices Topics API अ‍ॅक्सेस करण्याची अनुमती देते."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API अ‍ॅक्सेस करा"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"अ‍ॅप्लिकेशनला AdServices Attribution API अ‍ॅक्सेस करण्याची अनुमती देते."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API अ‍ॅक्सेस करा"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"अ‍ॅप्लिकेशनला AdServices Custom Audiences API अ‍ॅक्सेस करण्याची अनुमती देते."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"झूम नियंत्रणासाठी दोनदा टॅप करा"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"विजेट जोडू शकलो नाही."</string>
<string name="ime_action_go" msgid="5536744546326495436">"जा"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ॲप उपलब्ध नाही"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> आता उपलब्ध नाही."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध नाही"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"हे यावेळी तुमच्या <xliff:g id="DEVICE">%1$s</xliff:g> वर अ‍ॅक्सेस करू शकत नाही. त्याऐवजी तुमच्या Android TV डिव्हाइसवर अ‍ॅक्सेस करून पहा."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"हे यावेळी तुमच्या <xliff:g id="DEVICE">%1$s</xliff:g> वर अ‍ॅक्सेस करू शकत नाही. त्याऐवजी तुमच्या टॅबलेटवर अ‍ॅक्सेस करून पहा."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"हे यावेळी तुमच्या <xliff:g id="DEVICE">%1$s</xliff:g> वर अ‍ॅक्सेस करू शकत नाही. त्याऐवजी तुमच्या फोनवर अ‍ॅक्सेस करून पहा."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ला सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"फक्त यावेळी"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"अनुमती देऊ नका"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"तुमच्या डिव्हाइसवर काय होते ते डिव्हाइस लॉग रेकॉर्ड करते. समस्या शोधण्यासाठी आणि त्यांचे निराकरण करण्याकरिता ॲप्स हे लॉग वापरू शकतात.\n\nकाही लॉगमध्ये संवेदनशील माहिती असू शकते, त्यामुळे फक्त तुमचा विश्वास असलेल्या ॲप्सना सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती द्या. \n\nतुम्ही या ॲपला सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती न दिल्यास, ते तरीही त्याचा स्वतःचा लॉग अ‍ॅक्सेस करू शकते आणि तुमच्या डिव्हाइसचा उत्पादक तरीही काही लॉग किंवा तुमच्या डिव्हाइसवरील माहिती अ‍ॅक्सेस करू शकतो. अधिक जाणून घ्या"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"पुन्हा दाखवू नका"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ला <xliff:g id="APP_2">%2$s</xliff:g> चे तुकडे दाखवायचे आहेत"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"संपादित करा"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> हे बॅकग्राउंडमध्ये रन होत आहे आणि बॅटरी संपवत आहे. पुनरावलोकनासाठी टॅप करा."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> हे बऱ्याच कालावधीपासून बॅकग्राउंडमध्ये रन होत आहे. पुनरावलोकनासाठी टॅप करा."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ॲक्टिव्ह ॲप्स पहा"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"या डिव्हाइसवरून कॅमेरा अ‍ॅक्सेस करू शकत नाही"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"सिस्टीम भाषा"</string>
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index d14138aa267f..9c7d11d14c7c 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Membenarkan apl meminta kebenaran untuk mengabaikan pengoptimuman bateri untuk apl itu."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"buat pertanyaan untuk semua pakej"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Membenarkan apl melihat semua pakej yang dipasang."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"akses API Topik AdServices"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Membenarkan aplikasi mengakses API Topik AdServices."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"akses API Atribusi AdServices"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Membenarkan aplikasi mengakses API Atribusi AdServices."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"akses API Khalayak Tersuai AdServices"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Membenarkan aplikasi mengakses API Khalayak Tersuai AdServices."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Ketik dua kali untuk mendapatkan kawalan zum"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Tidak dapat menambahkan widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Pergi"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Apl tidak tersedia"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia sekarang."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> tidak tersedia"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Kebenaran diperlukan"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Aplikasi ini tidak boleh diakses pada <xliff:g id="DEVICE">%1$s</xliff:g> anda pada masa ini. Cuba pada peranti Android TV anda."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Aplikasi ini tidak boleh diakses pada <xliff:g id="DEVICE">%1$s</xliff:g> anda pada masa ini. Cuba pada tablet anda."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Aplikasi ini tidak boleh diakses pada <xliff:g id="DEVICE">%1$s</xliff:g> anda pada masa ini. Cuba pada telefon anda."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Benarkan <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> mengakses semua log peranti?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Kali ini sahaja"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Jangan benarkan"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Log peranti merekodkan perkara yang berlaku pada peranti anda. Apl dapat menggunakan log ini untuk menemukan dan membetulkan isu.\n\nSesetengah log mungkin mengandungi maklumat sensitif, jadi benarkan apl yang anda percaya sahaja untuk mengakses semua log peranti. \n\nJika anda tidak membenarkan apl ini mengakses semua log peranti, apl masih boleh mengakses log sendiri dan pengilang peranti anda mungkin masih boleh mengakses sesetengah log atau maklumat pada peranti anda. Ketahui lebih lanjut"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Jangan tunjuk lagi"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> mahu menunjukkan <xliff:g id="APP_2">%2$s</xliff:g> hirisan"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> dijalankan di latar belakang dan melemahkan bateri. Ketik untuk semak."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g>sedang berjalan di latar belakang untuk masa yang lama. Ketik untuk menyemak."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Semak apl aktif"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Tidak dapat mengakses kamera daripada peranti ini"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Bahasa sistem"</string>
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 3e53812fabea..cd8b356538cd 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"ဘက်ထရီ ပိုမိုကောင်းမွန်အောင် ပြုလုပ်ခြင်းကို လျစ်လျူရှုရန်အတွက် ခွင့်ပြုချက်တောင်းရန် အက်ပ်ကို ခွင့်ပြုပါ။"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"ပက်ကေ့ဂျ်အားလုံးကို မေးမြန်းခြင်း"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"ထည့်သွင်းထားသော ပက်ကေ့ဂျ်အားလုံး ကြည့်ရန် အက်ပ်ကို ခွင့်ပြုပါ။"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API သုံးခွင့်"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"AdServices Topics API ကို အပလီကေးရှင်းတစ်ခုအား သုံးခွင့်ပေးနိုင်သည်။"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API များ သုံးခွင့်"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"AdServices Attribution API များကို အပလီကေးရှင်းတစ်ခုအား သုံးခွင့်ပေးနိုင်သည်။"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API သုံးခွင့်"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"AdServices Custom Audiences API ကို အပလီကေးရှင်းတစ်ခုအား သုံးခွင့်ပေးနိုင်သည်။"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ဇူးမ်အသုံးပြုရန် နှစ်ချက်တို့ပါ"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"ဝဒ်ဂျက်ထည့်လို့ မရပါ"</string>
<string name="ime_action_go" msgid="5536744546326495436">"သွားပါ"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"အက်ပ်ကို မရနိုင်ပါ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကို ယခု မရနိုင်ပါ။"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> မရနိုင်ပါ"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"၎င်းအား ယခု သင့် <xliff:g id="DEVICE">%1$s</xliff:g> တွင် ဝင်၍မရပါ။ ယင်းအစား Android TV စက်တွင် စမ်းကြည့်ပါ။"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"၎င်းအား ယခု သင့် <xliff:g id="DEVICE">%1$s</xliff:g> တွင် ဝင်၍မရပါ။ ယင်းအစား တက်ဘလက်တွင် စမ်းကြည့်ပါ။"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"၎င်းအား ယခု သင့် <xliff:g id="DEVICE">%1$s</xliff:g> တွင် ဝင်၍မရပါ။ ယင်းအစား ဖုန်းတွင် စမ်းကြည့်ပါ။"</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ကို စက်မှတ်တမ်းအားလုံး သုံးခွင့်ပြုမလား။"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"ဤတစ်ကြိမ်သာ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"ခွင့်မပြုပါ"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"သင့်စက်ရှိ အဖြစ်အပျက်များကို စက်မှတ်တမ်းများက မှတ်တမ်းတင်သည်။ အက်ပ်များက ပြဿနာများ ရှာဖွေပြီးဖြေရှင်းရန် ဤမှတ်တမ်းများကို သုံးနိုင်သည်။\n\nအချို့မှတ်တမ်းများတွင် သတိထားရမည့်အချက်အလက်များ ပါဝင်နိုင်သဖြင့် စက်မှတ်တမ်းအားလုံးကို ယုံကြည်ရသည့် အက်ပ်များကိုသာ သုံးခွင့်ပြုပါ။ \n\nဤအက်ပ်ကို စက်မှတ်တမ်းအားလုံး သုံးခွင့်မပြုသော်လည်း ၎င်းက ကိုယ်ပိုင်မှတ်တမ်းကို သုံးနိုင်ဆဲဖြစ်ပြီး သင့်စက်ရှိ အချို့မှတ်တမ်းများ (သို့) အချက်အလက်များကို သင့်စက်ထုတ်လုပ်သူက သုံးနိုင်ပါသေးသည်။ ပိုမိုလေ့လာရန်"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"နောက်ထပ်မပြပါနှင့်"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> သည် <xliff:g id="APP_2">%2$s</xliff:g> ၏အချပ်များကို ပြသလိုသည်"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"တည်းဖြတ်ရန်"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> သည် နောက်ခံတွင်ပွင့်နေပြီး ဘက်ထရီအားကုန်စေသည်။ ပြန်ကြည့်ရန် တို့ပါ။"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> သည် နောက်ခံတွင် အချိန်အတော်ကြာပွင့်နေသည်။ ပြန်ကြည့်ရန် တို့ပါ။"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ပွင့်နေသည့်အက်ပ်များ စစ်ဆေးရန်"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"ကင်မရာကို ဤစက်မှ အသုံးမပြုနိုင်ပါ"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"စနစ်၏ ဘာသာစကား"</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 27fa108bc22e..efca7cd756ee 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Gjør det mulig for apper å be om tillatelse til å ignorere batterioptimaliseringer for disse appene."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"søk i alle pakker"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Lar en app se alle installerte pakker."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"bruke AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Gir en app tilgang til AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"bruke AdServices Attribution-API-er"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Gir en app tilgang til AdServices Attribution-API-er."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"bruke AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Gir en app tilgang til AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Trykk to ganger for zoomkontroll"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Kunne ikke legge til modulen."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Utfør"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgjengelig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgjengelig for øyeblikket."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> er utilgjengelig"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Dette er ikke tilgjengelig på <xliff:g id="DEVICE">%1$s</xliff:g> for øyeblikket. Prøv på Android TV-enheten din i stedet."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Dette er ikke tilgjengelig på <xliff:g id="DEVICE">%1$s</xliff:g> for øyeblikket. Prøv på nettbrettet ditt i stedet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Dette er ikke tilgjengelig på <xliff:g id="DEVICE">%1$s</xliff:g> for øyeblikket. Prøv på telefonen din i stedet."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Vil du gi <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> tilgang til alle enhetslogger?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Bare denne gangen"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ikke tillat"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Enhetslogger registrerer det som skjer på enheten din. Apper kan bruke disse loggene til å finne og løse problemer.\n\nNoen logger kan inneholde sensitiv informasjon, så du bør bare gi tilgang til alle enhetslogger til apper du stoler på. \n\nHvis du ikke gir denne appen tilgang til alle enhetslogger, har den fremdeles tilgang til sine egne logger, og enhetsprodusenten kan fremdeles ha tilgang til noen logger eller noe informasjon på enheten din. Finn ut mer"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ikke vis igjen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vil vise <xliff:g id="APP_2">%2$s</xliff:g>-utsnitt"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Endre"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> kjører i bakgrunnen og bruker batteri. Trykk for å gjennomgå."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> kjører lenge i bakgrunnen. Trykk for å gjennomgå."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Sjekk aktive apper"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Du har ikke tilgang til kameraet fra denne enheten"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Systemspråk"</string>
</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 6f1d72e5bc47..368fa46e7515 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"कुनै एपलाई त्यसका ब्याट्री सम्बन्धी अनुकूलनहरूलाई बेवास्ता गर्नाका लागि अनुमति माग्न दिन्छ।"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"सबै प्याकेजहरू खोज्नुहोस्"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"यसले यस एपलाई इन्स्टल गरिएका सबै प्याकेजहरू हेर्ने अनुमति दिन्छ।"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API प्रयोग गर्ने अनुमति"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"एपलाई AdServices Topics API प्रयोग गर्ने अनुमति दिन्छ।"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API प्रयोग गर्ने अनुमति"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"एपलाई AdServices Attribution API प्रयोग गर्ने अनुमति दिन्छ।"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API प्रयोग गर्ने अनुमति"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"एपलाई AdServices Custom Audiences API प्रयोग गर्ने अनुमति दिन्छ।"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"जुम नियन्त्रणको लागि दुई चोटि ट्याप गर्नुहोस्"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"विजेट थप गर्न सकिँदैन।"</string>
<string name="ime_action_go" msgid="5536744546326495436">"जानुहोस्"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"एप उपलब्ध छैन"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> अहिले उपलब्ध छैन।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध छैन"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"यस बखत तपाईंको <xliff:g id="DEVICE">%1$s</xliff:g> मा यो एप स्ट्रिम गर्न मिल्दैन। बरु तपाईंको Android TV डिभाइसमा स्ट्रिम गरी हेर्नुहोस्।"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"यस बखत तपाईंको <xliff:g id="DEVICE">%1$s</xliff:g> मा यो एप स्ट्रिम गर्न मिल्दैन। बरु तपाईंको ट्याब्लेटमा स्ट्रिम गरी हेर्नुहोस्।"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"यस बखत तपाईंको <xliff:g id="DEVICE">%1$s</xliff:g> मा यो एप स्ट्रिम गर्न मिल्दैन। बरु तपाईंको फोनमा स्ट्रिम गरी हेर्नुहोस्।"</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> लाई डिभाइसका सबै लग हेर्ने अनुमति दिने हो?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"यस पटक मात्र"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"अनुमति नदिनुहोस्"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"डिभाइसका लगमा तपाईंको डिभाइसमा भएका विभिन्न गतिविधिको अभिलेख राखिन्छ। एपहरू यी लगका आधारमा समस्या पत्ता लगाउन र तिनको समाधान गर्न सक्छन्।\n\nकेही लगहरूमा संवेदनशील जानकारी समावेश हुन सक्ने भएकाले आफूले भरोसा गर्ने एपलाई मात्र डिभाइसका सबै लग हेर्ने अनुमति दिनुहोस्। \n\nतपाईंले यो एपलाई डिभाइसका सबै लग हेर्ने अनुमति दिनुभएन भने पनि यसले आफ्नै लग भने हेर्न सक्छ। यसै गरी तपाईंको डिभाइसको उत्पादकले पनि तपाईंको डिभाइसमा भएका केही लग वा जानकारी हेर्न सक्ने सम्भावना हुन्छ। थप जान्नुहोस्"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"फेरि नदेखाइयोस्"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ले <xliff:g id="APP_2">%2$s</xliff:g> का स्लाइसहरू देखाउन चाहन्छ"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"सम्पादन गर्नुहोस्"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ब्याकग्राउन्डमा चलिरहेको हुनाले ब्याट्री खपत भइरहेको छ। समीक्षा गर्न ट्याप गर्नुहोस्।"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> लामो समयदेखि ब्याकग्राउन्डमा चलिरहेको छ। समीक्षा गर्न ट्याप गर्नुहोस्।"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"कुन कुन एप सक्रिय छ भन्ने कुरा जाँच्नुहोस्"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"यो डिभाइसमा भएको क्यामेरा प्रयोग गर्न सकिएन"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"सिस्टमको भाषा"</string>
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index cbd2f54112f1..0b5dde11186e 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Hiermee kan een app rechten vragen om batterijoptimalisatie voor die app te negeren."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"alle pakketten opvragen"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Hiermee kan een app alle geïnstalleerde pakketten zien."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"toegang tot de AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Geeft een app toegang tot de AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"toegang tot AdServices Attribution API\'s"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Geeft een app toegang tot AdServices Attribution API\'s."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"toegang tot de AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Geeft een app toegang tot de AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Tik twee keer voor zoomregeling"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Kan widget niet toevoegen."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Ga"</string>
@@ -1688,7 +1682,7 @@
<string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"Als je <xliff:g id="SERVICE">%1$s</xliff:g> aanzet, gebruikt je apparaat geen schermvergrendeling om de gegevensversleuteling te verbeteren."</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"Volledige controle is gepast voor apps die je helpen met toegankelijkheid, maar voor de meeste apps is het ongepast."</string>
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Scherm bekijken en bedienen"</string>
- <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"De functie kan alle content op het scherm lezen en content bovenop andere apps weergeven."</string>
+ <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"De functie kan alle content op het scherm lezen en content bovenop andere apps bekijken."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Acties bekijken en uitvoeren"</string>
<string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"De functie kan je interacties met een app of een hardwaresensor bijhouden en namens jou met apps communiceren."</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Toestaan"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"App is niet beschikbaar"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is momenteel niet beschikbaar."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> niet beschikbaar"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Je hebt hier nu geen toegang toe op je <xliff:g id="DEVICE">%1$s</xliff:g>. Probeer het in plaats daarvan op je Android TV-apparaat."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Je hebt hier nu geen toegang toe op je <xliff:g id="DEVICE">%1$s</xliff:g>. Probeer het in plaats daarvan op je tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Je hebt hier nu geen toegang toe op je <xliff:g id="DEVICE">%1$s</xliff:g>. Probeer het in plaats daarvan op je telefoon."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> toegang geven tot alle apparaatlogboeken?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Alleen deze keer"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Niet toestaan"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Apparaatlogboeken leggen vast wat er op je apparaat gebeurt. Apps kunnen deze logboeken gebruiken om problemen op te sporen en te verhelpen.\n\nSommige logboeken kunnen gevoelige informatie bevatten, dus geef alleen apps die je vertrouwt toegang tot alle apparaatlogboeken. \n\nAls je deze app geen toegang tot alle apparaatlogboeken geeft, heeft de app nog wel toegang tot de eigen logboeken. De fabrikant van je apparaat heeft misschien nog steeds toegang tot bepaalde logboeken of informatie op je apparaat. Meer informatie"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Niet opnieuw tonen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wil segmenten van <xliff:g id="APP_2">%2$s</xliff:g> tonen"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Bewerken"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> wordt uitgevoerd op de achtergrond en verbruikt veel batterijlading. Tik om te bekijken."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> wordt al lange tijd uitgevoerd op de achtergrond. Tik om te bekijken."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Actieve apps checken"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Kan geen toegang krijgen tot de camera vanaf dit apparaat"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Systeemtaal"</string>
</resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 775d320e27cf..adf6c8f4b469 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"ଆପ୍‍ ପାଇଁ ବ୍ୟାଟେରୀ ଅନୁକୂଳନ ଏଡ଼ାଇବାର ଅନୁମତି ମାଗିବା ନିମନ୍ତେ ଆପ୍‍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"ସବୁ ପ୍ୟାକେଜ୍ ବିଷୟରେ କ୍ୱେରୀ କରନ୍ତୁ"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"ଇନଷ୍ଟଲ୍ କରାଯାଇଥିବା ସମସ୍ତ ପ୍ୟାକେଜକୁ ଦେଖିବା ପାଇଁ ଏକ ଆପକୁ ଅନୁମତି ଦିଏ।"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics APIକୁ ଆକ୍ସେସ କରନ୍ତୁ"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"AdServices Topics APIକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏକ ଆପ୍ଲିକେସନକୁ ଅନୁମତି ଦିଏ।"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution APIଗୁଡ଼ିକୁ ଆକ୍ସେସ କରନ୍ତୁ"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"AdServices Attribution APIଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏକ ଆପ୍ଲିକେସନକୁ ଅନୁମତି ଦିଏ।"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences APIକୁ ଆକ୍ସେସ କରନ୍ତୁ"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"AdServices Custom Audiences APIକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏକ ଆପ୍ଲିକେସନକୁ ଅନୁମତି ଦିଏ।"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ଜୁମ୍ ନିୟନ୍ତ୍ରଣ ପାଇଁ ଦୁଇଥର ଟାପ୍‌ କରନ୍ତୁ"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"ୱିଜେଟ୍‍ ଯୋଡ଼ିପାରିବ ନାହିଁ।"</string>
<string name="ime_action_go" msgid="5536744546326495436">"ଯାଆନ୍ତୁ"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ଆପ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବର୍ତ୍ତମାନ ଉପଲବ୍ଧ ନାହିଁ।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ବର୍ତ୍ତମାନ ଏହାକୁ ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g>ରେ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ Android TV ଡିଭାଇସରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ବର୍ତ୍ତମାନ ଏହାକୁ ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g>ରେ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ ଟାବଲେଟରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ବର୍ତ୍ତମାନ ଏହାକୁ ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g>ରେ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ ଫୋନରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"କେବଳ ଏହି ଥର"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"ଆପଣଙ୍କ ଡିଭାଇସରେ ଯାହା ହୁଏ ତାହା ଡିଭାଇସ ଲଗଗୁଡ଼ିକ ରେକର୍ଡ କରେ। ସମସ୍ୟାଗୁଡ଼ିକୁ ଖୋଜି ସମାଧାନ କରିବାକୁ ଆପ୍ସ ଏହି ଲଗଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିପାରିବ।\n\nକିଛି ଲଗରେ ସମ୍ବେଦନଶୀଳ ସୂଚନା ଥାଇପାରେ, ତେଣୁ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଆପଣ ବିଶ୍ୱାସ କରୁଥିବା ଆପ୍ସକୁ ହିଁ ଅନୁମତି ଦିଅନ୍ତୁ। \n\nଯଦି ଆପଣ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଆପକୁ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ, ତେବେ ବି ଏହା ନିଜର ଡିଭାଇସ ଲଗଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିପାରିବ ଏବଂ ଆପଣଙ୍କ ଡିଭାଇସର ନିର୍ମାତା ଏବେ ବି ଆପଣଙ୍କର ଡିଭାଇସରେ କିଛି ଲଗ କିମ୍ବା ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ସକ୍ଷମ ହୋଇପାରନ୍ତି। ଅଧିକ ଜାଣନ୍ତୁ"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"ପୁଣି ଦେଖାନ୍ତୁ ନାହିଁ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>, <xliff:g id="APP_2">%2$s</xliff:g> ସ୍ଲାଇସ୍‌କୁ ଦେଖାଇବା ପାଇଁ ଚାହେଁ"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ଏଡିଟ୍ କରନ୍ତୁ"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g>ଟି ପୃଷ୍ଠପଟରେ ଚାଲୁଥିବା ଯୋଗୁଁ ବ୍ୟାଟେରୀର ଚାର୍ଜ ସରିଯାଉଛି। ସମୀକ୍ଷା କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ଦୀର୍ଘ ସମୟ ଧରି ପୃଷ୍ଠପଟରେ ଚାଲୁଛି। ସମୀକ୍ଷା କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ସକ୍ରିୟ ଆପଗୁଡ଼ିକୁ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"ଏହି ଡିଭାଇସରୁ କ୍ୟାମେରାକୁ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"ସିଷ୍ଟମ ଭାଷା"</string>
</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 94d1507e6caf..1b3cc29b14cd 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"ਕਿਸੇ ਐਪ ਨੂੰ ਉਸ ਵਾਸਤੇ ਬੈਟਰੀ ਸੁਯੋਗਤਾਵਾਂ ਨੂੰ ਅਣਡਿੱਠ ਕਰਨ ਲਈ ਇਜਾਜ਼ਤ ਵਾਸਤੇ ਪੁੱਛਣ ਲਈ ਆਗਿਆ ਦਿੰਦੀ ਹੈ।"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"ਸਾਰੇ ਪੈਕੇਜਾਂ ਬਾਰੇ ਪੁੱਛਗਿੱਛ"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"ਇਸ ਨਾਲ ਐਪ ਨੂੰ ਸਥਾਪਤ ਕੀਤੇ ਸਾਰੇ ਪੈਕੇਜ ਦੇਖਣ ਦੀ ਇਜਾਜ਼ਤ ਮਿਲਦੀ ਹੈ।"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API ਤੱਕ ਪਹੁੰਚ ਮਿਲਦੀ ਹੈ"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"ਐਪਲੀਕੇਸ਼ਨ ਨੂੰ AdServices Topics API ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਮਿਲਦੀ ਹੈ।"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API ਤੱਕ ਪਹੁੰਚ ਮਿਲਦੀ ਹੈ"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"ਐਪਲੀਕੇਸ਼ਨ ਨੂੰ AdServices Attribution API ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਮਿਲਦੀ ਹੈ।"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API ਤੱਕ ਪਹੁੰਚ ਮਿਲਦੀ ਹੈ"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"ਐਪਲੀਕੇਸ਼ਨ ਨੂੰ AdServices Custom Audiences API ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਮਿਲਦੀ ਹੈ।"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ਜ਼ੂਮ ਕੰਟਰੋਲ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"ਵਿਜੇਟ ਸ਼ਾਮਲ ਨਹੀਂ ਹੋ ਸਕਿਆ।"</string>
<string name="ime_action_go" msgid="5536744546326495436">"ਜਾਓ"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ਐਪ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਇਸ ਵੇਲੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ਇਸ ਸਮੇਂ ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> \'ਤੇ ਇਸ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ Android TV ਡੀਵਾਈਸ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ਇਸ ਸਮੇਂ ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> \'ਤੇ ਇਸ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ ਟੈਬਲੈੱਟ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ਇਸ ਸਮੇਂ ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> \'ਤੇ ਇਸ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ ਫ਼ੋਨ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"ਕੀ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ਨੂੰ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"ਸਿਰਫ਼ ਇਸ ਵਾਰ"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"ਆਗਿਆ ਨਾ ਦਿਓ"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"ਡੀਵਾਈਸ ਲੌਗਾਂ ਵਿੱਚ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀਆਂ ਕਾਰਵਾਈਆਂ ਰਿਕਾਰਡ ਹੁੰਦੀਆਂ ਹਨ। ਐਪਾਂ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਲੱਭਣ ਅਤੇ ਉਨ੍ਹਾਂ ਦਾ ਹੱਲ ਕਰਨ ਲਈ ਇਨ੍ਹਾਂ ਲੌਗਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੀਆਂ ਹਨ।\n\nਕੁਝ ਲੌਗਾਂ ਵਿੱਚ ਸੰਵੇਦਨਸ਼ੀਲ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ, ਇਸ ਲਈ ਸਿਰਫ਼ ਆਪਣੀਆਂ ਭਰੋਸੇਯੋਗ ਐਪਾਂ ਨੂੰ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ। \n\nਜੇ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦੇ ਹੋ, ਤਾਂ ਇਹ ਹਾਲੇ ਵੀ ਆਪਣੇ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ ਅਤੇ ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਨਿਰਮਾਤਾ ਹਾਲੇ ਵੀ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਮੌਜੂਦ ਕੁਝ ਲੌਗਾਂ ਜਾਂ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦਾ ਹੈ। ਹੋਰ ਜਾਣੋ"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ਦੀ <xliff:g id="APP_2">%2$s</xliff:g> ਦੇ ਹਿੱਸੇ ਦਿਖਾਉਣ ਦੀ ਇੱਛਾ ਹੈ"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ਸੰਪਾਦਨ ਕਰੋ"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲ ਰਹੀ ਹੈ ਅਤੇ ਬੈਟਰੀ ਦੀ ਖਪਤ ਕਰ ਰਹੀ ਹੈ। ਸਮੀਖਿਆ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ਲੰਮੇ ਸਮੇਂ ਤੋਂ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲ ਰਹੀ ਹੈ। ਸਮੀਖਿਆ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ਕਿਰਿਆਸ਼ੀਲ ਐਪਾਂ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"ਇਸ ਡੀਵਾਈਸ ਤੋਂ ਕੈਮਰੇ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"ਸਿਸਟਮ ਦੀ ਭਾਸ਼ਾ"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 7cf189de7e7f..91f0c89c45c9 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1453,12 +1453,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Zezwala aplikacji na proszenie o uprawnienia do ignorowania optymalizacji wykorzystania baterii w przypadku danej aplikacji."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"zapytanie o wszystkie pakiety"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Pozwala aplikacji wyświetlać wszystkie zainstalowane pakiety."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"Dostęp do AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Zezwala na dostęp aplikacji do AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"Dostęp do interfejsów AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Zezwala na dostęp aplikacji do interfejsów AdServices Attribution API."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"Dostęp do AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Zezwala na dostęp aplikacji do AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Dotknij dwukrotnie, aby sterować powiększeniem"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Nie można dodać widżetu."</string>
<string name="ime_action_go" msgid="5536744546326495436">"OK"</string>
@@ -1941,6 +1935,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacja jest niedostępna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest obecnie niedostępna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – brak dostępu"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"W tej chwili nie można z tego skorzystać na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>. Użyj urządzenia z Androidem TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"W tej chwili nie można z tego skorzystać na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>. Użyj tabletu."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"W tej chwili nie można z tego skorzystać na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>. Użyj telefonu."</string>
@@ -2036,7 +2032,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Zezwolić aplikacji <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> na dostęp do wszystkich dzienników urządzenia?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Tylko tym razem"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nie zezwalaj"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Dzienniki urządzenia zapisują, co dzieje się na urządzeniu. Aplikacje mogą ich używać do wykrywania i rozwiązywania problemów.\n\nNiektóre dzienniki mogą zawierać poufne dane, dlatego na dostęp do wszystkich dzienników zezwalaj tylko aplikacjom, którym ufasz. \n\nNawet jeśli nie zezwolisz tej aplikacji na dostęp do wszystkich dzienników na urządzeniu, będzie miała dostęp do własnych, a producent urządzenia będzie mógł korzystać z niektórych dzienników na urządzeniu. Więcej informacji"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Nie pokazuj ponownie"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikacja <xliff:g id="APP_0">%1$s</xliff:g> chce pokazywać wycinki z aplikacji <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edytuj"</string>
@@ -2270,7 +2267,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Aplikacja <xliff:g id="APP">%1$s</xliff:g> działa w tle i zużywa baterię. Kliknij, aby sprawdzić."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Aplikacja <xliff:g id="APP">%1$s</xliff:g> długo działa w tle. Kliknij, aby sprawdzić."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Sprawdź aktywne aplikacje"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Nie można uzyskać dostępu do aparatu z tego urządzenia"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Język systemu"</string>
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 75b46e5be4fe..843f533f26fa 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -553,7 +553,7 @@
<string name="permlab_nfc" msgid="1904455246837674977">"controlar a comunicação a curta distância"</string>
<string name="permdesc_nfc" msgid="8352737680695296741">"Permite que o app se comunique com leitores, cartões e etiqueta NFC (comunicação a curta distância)."</string>
<string name="permlab_disableKeyguard" msgid="3605253559020928505">"desativar o bloqueio de tela"</string>
- <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"Permite que o app desative o bloqueio de teclas e qualquer segurança por senha associada. Por exemplo, o telefone desativa o bloqueio de telas ao receber uma chamada e o reativa quando a chamada é finalizada."</string>
+ <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"Permite que o app desative o bloqueio de teclas e qualquer segurança por senha associada. Por exemplo, o telefone desativa o bloqueio de telas ao receber uma ligação e o reativa quando a chamada é finalizada."</string>
<string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"Solicitar complexidade do bloqueio de tela"</string>
<string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"Permite que o app saiba o nível de complexidade do bloqueio de tela (alto, médio, baixo ou nenhum), que indica o intervalo possível de comprimento e o tipo de bloqueio de tela. O app também pode sugerir a atualização do bloqueio de tela até um certo nível, mas os usuários podem ignorar a sugestão. O bloqueio de tela não é armazenado em texto simples, então o app não tem acesso à senha exata."</string>
<string name="permlab_postNotification" msgid="4875401198597803658">"mostrar notificações"</string>
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Permite que um app peça permissão para ignorar as otimizações de bateria para esse app."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"consultar todos os pacotes"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Permite que um app veja todos os pacotes instalados."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"acessar a API AdServices Topics"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Permite que um aplicativo tenha acesso à API AdServices Topics."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"acessar APIs AdServices Attribution"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Permite que um aplicativo tenha acesso a APIs AdServices Attribution."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"acessar a API AdServices Custom Audiences"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Permite que um aplicativo tenha acesso à API AdServices Custom Audiences."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Toque duas vezes para ter controle do zoom"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Não foi possível adicionar widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Ir"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"No momento, não é possível acessar esse app pelo <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo dispositivo Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"No momento, não é possível acessar esse app pelo <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo seu tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"No momento, não é possível acessar esse app pelo <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo seu smartphone."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Permitir que o app <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> acesse todos os registros do dispositivo?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Apenas esta vez"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Não permitir"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Os registros do dispositivo gravam o que acontece nele. Os apps podem usar esses registros para encontrar e corrigir problemas.\n\nAlguns registros podem conter informações sensíveis, então permita que apenas os apps em que você confia acessem os registros. \n\nSe você não permitir que este app acesse todos os registros do dispositivo, ele ainda vai poder acessar os próprios registros. O fabricante do dispositivo também pode ter acesso a alguns registros ou informações. Saiba mais"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Não mostrar novamente"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quer mostrar partes do app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> está sendo executado em segundo plano e drenando a energia da bateria. Toque para revisar."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> está sendo executado em segundo plano faz muito tempo. Toque para revisar."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Verificar apps ativos"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Não é possível acessar a câmera neste dispositivo"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Idioma do sistema"</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 526806550085..c0ac4fd9bdf0 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Permite que uma app solicite autorização para ignorar as otimizações da bateria para a mesma."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"consultar todos os pacotes"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Permite a uma app ver todos os pacotes instalados."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"aceder à API AdServices Topics"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Permite a uma aplicação aceder à API AdServices Topics."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"aceder às APIs AdServices Attribution"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Permite a uma aplicação aceder às APIs AdServices Attribution."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"aceder à API AdServices Custom Audiences"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Permite a uma aplicação aceder à API AdServices Custom Audiences."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Tocar duas vezes para controlar o zoom"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Não foi possível adicionar widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Ir"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"A app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"De momento, a app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"De momento, não é possível aceder a esta app no seu <xliff:g id="DEVICE">%1$s</xliff:g>. Em alternativa, experimente no dispositivo Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"De momento, não é possível aceder a esta app no seu <xliff:g id="DEVICE">%1$s</xliff:g>. Em alternativa, experimente no tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"De momento, não é possível aceder a esta app no seu <xliff:g id="DEVICE">%1$s</xliff:g>. Em alternativa, experimente no telemóvel."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Permitir que a app <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> aceda a todos os registos do dispositivo?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Apenas desta vez"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Não permitir"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Os registos do dispositivo documentam o que ocorre no seu dispositivo. As apps podem usar esses registos para detetar e corrigir problemas.\n\nAlguns registos podem conter informações confidenciais, pelo que o acesso a todos os registos do dispositivo deve apenas ser permitido às apps nas quais confia. \n\nSe não permitir o acesso desta app a todos os registos do dispositivo, a mesma pode ainda assim aceder aos seus próprios registos e o fabricante do dispositivo pode continuar a aceder a alguns registos ou informações no seu dispositivo. Saiba mais"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Não mostrar de novo"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"A app <xliff:g id="APP_0">%1$s</xliff:g> pretende mostrar partes da app <xliff:g id="APP_2">%2$s</xliff:g>."</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> está a ser executada em 2.º plano e a consumir muita bateria. Toque para analisar."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"A app <xliff:g id="APP">%1$s</xliff:g> está a ser executada em segundo plano há muito tempo. Toque para analisar."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Verificar apps ativas"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Não é possível aceder à câmara a partir deste dispositivo"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Idioma do sistema"</string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 75b46e5be4fe..843f533f26fa 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -553,7 +553,7 @@
<string name="permlab_nfc" msgid="1904455246837674977">"controlar a comunicação a curta distância"</string>
<string name="permdesc_nfc" msgid="8352737680695296741">"Permite que o app se comunique com leitores, cartões e etiqueta NFC (comunicação a curta distância)."</string>
<string name="permlab_disableKeyguard" msgid="3605253559020928505">"desativar o bloqueio de tela"</string>
- <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"Permite que o app desative o bloqueio de teclas e qualquer segurança por senha associada. Por exemplo, o telefone desativa o bloqueio de telas ao receber uma chamada e o reativa quando a chamada é finalizada."</string>
+ <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"Permite que o app desative o bloqueio de teclas e qualquer segurança por senha associada. Por exemplo, o telefone desativa o bloqueio de telas ao receber uma ligação e o reativa quando a chamada é finalizada."</string>
<string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"Solicitar complexidade do bloqueio de tela"</string>
<string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"Permite que o app saiba o nível de complexidade do bloqueio de tela (alto, médio, baixo ou nenhum), que indica o intervalo possível de comprimento e o tipo de bloqueio de tela. O app também pode sugerir a atualização do bloqueio de tela até um certo nível, mas os usuários podem ignorar a sugestão. O bloqueio de tela não é armazenado em texto simples, então o app não tem acesso à senha exata."</string>
<string name="permlab_postNotification" msgid="4875401198597803658">"mostrar notificações"</string>
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Permite que um app peça permissão para ignorar as otimizações de bateria para esse app."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"consultar todos os pacotes"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Permite que um app veja todos os pacotes instalados."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"acessar a API AdServices Topics"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Permite que um aplicativo tenha acesso à API AdServices Topics."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"acessar APIs AdServices Attribution"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Permite que um aplicativo tenha acesso a APIs AdServices Attribution."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"acessar a API AdServices Custom Audiences"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Permite que um aplicativo tenha acesso à API AdServices Custom Audiences."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Toque duas vezes para ter controle do zoom"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Não foi possível adicionar widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Ir"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"No momento, não é possível acessar esse app pelo <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo dispositivo Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"No momento, não é possível acessar esse app pelo <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo seu tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"No momento, não é possível acessar esse app pelo <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo seu smartphone."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Permitir que o app <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> acesse todos os registros do dispositivo?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Apenas esta vez"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Não permitir"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Os registros do dispositivo gravam o que acontece nele. Os apps podem usar esses registros para encontrar e corrigir problemas.\n\nAlguns registros podem conter informações sensíveis, então permita que apenas os apps em que você confia acessem os registros. \n\nSe você não permitir que este app acesse todos os registros do dispositivo, ele ainda vai poder acessar os próprios registros. O fabricante do dispositivo também pode ter acesso a alguns registros ou informações. Saiba mais"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Não mostrar novamente"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quer mostrar partes do app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> está sendo executado em segundo plano e drenando a energia da bateria. Toque para revisar."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> está sendo executado em segundo plano faz muito tempo. Toque para revisar."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Verificar apps ativos"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Não é possível acessar a câmera neste dispositivo"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Idioma do sistema"</string>
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 0c9e87a82869..6d3f939a9c1c 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1452,12 +1452,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Permite unei aplicații să solicite permisiunea de a ignora optimizările bateriei pentru aplicația respectivă."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"să interogheze toate pachetele"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Permite unei aplicații să vadă toate pachetele instalate."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"să acceseze API-ul AdServices Topics"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Permite unei aplicații să acceseze API-ul AdServices Topics."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"să acceseze API-urile AdServices Attribution"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Permite unei aplicații să acceseze API-urile AdServices Attribution."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"să acceseze API-ul AdServices Custom Audiences"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Permite unei aplicații să acceseze API-ul AdServices Custom Audiences."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Apăsați de două ori pentru a controla mărirea/micșorarea"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Nu s-a putut adăuga widgetul."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Accesați"</string>
@@ -1940,6 +1934,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplicația nu este disponibilă"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu este disponibilă momentan."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nu este disponibilă"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Necesită permisiune"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Aplicația nu poate fi accesată pe <xliff:g id="DEVICE">%1$s</xliff:g> momentan. Încercați pe dispozitivul Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Aplicația nu poate fi accesată pe <xliff:g id="DEVICE">%1$s</xliff:g> momentan. Încercați pe tabletă."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Aplicația nu poate fi accesată pe <xliff:g id="DEVICE">%1$s</xliff:g> momentan. Încercați pe telefon."</string>
@@ -2035,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Permiteți ca <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> să acceseze toate jurnalele dispozitivului?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Doar de data aceasta"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nu permiteți"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Jurnalele dispozitivului înregistrează activitatea de pe dispozitivul dvs. Aplicațiile pot folosi aceste jurnale pentru a identifica și a remedia probleme.\n\nUnele jurnale pot să conțină informații sensibile, prin urmare permiteți accesul la toate jurnalele dispozitivului doar aplicațiilor în care aveți încredere. \n\nDacă nu permiteți accesul aplicației la toate jurnalele dispozitivului, aceasta poate în continuare să acceseze propriile jurnale și este posibil ca producătorul dispozitivului să acceseze în continuare unele jurnale sau informații de pe dispozitiv. Aflați mai multe"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Nu mai afișa"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vrea să afișeze porțiuni din <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editați"</string>
@@ -2269,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> rulează în fundal și consumă bateria. Atingeți pentru a examina."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> rulează în fundal mult timp. Atingeți pentru a examina."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Verificați aplicațiile active"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Nu se poate accesa camera foto de pe acest dispozitiv"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Limba sistemului"</string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 04ffd3b404bc..d1e40f56e66c 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -427,14 +427,10 @@
<string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"Приложение сможет вносить изменения в список вызовов планшетного ПК и данные о входящих и исходящих звонках. Вредоносные приложения смогут воспользоваться этим для удаления или изменения информации о звонках."</string>
<string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"Приложение сможет изменять список вызовов и данные о входящих и исходящих звонках на устройстве Android TV. Вредоносные программы смогут воспользоваться этим для удаления или изменения информации о звонках."</string>
<string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"Приложение сможет вносить изменения в список вызовов телефона и данные о входящих и исходящих звонках. Вредоносные приложения смогут воспользоваться этим для удаления или изменения информации о звонках."</string>
- <!-- no translation found for permlab_bodySensors (662918578601619569) -->
- <skip />
- <!-- no translation found for permdesc_bodySensors (7652650410295512140) -->
- <skip />
- <!-- no translation found for permlab_bodySensors_background (4912560779957760446) -->
- <skip />
- <!-- no translation found for permdesc_bodySensors_background (8870726027557749417) -->
- <skip />
+ <string name="permlab_bodySensors" msgid="662918578601619569">"Доступ к данным нательных датчиков, когда приложение используется"</string>
+ <string name="permdesc_bodySensors" product="default" msgid="7652650410295512140">"Когда приложение используется, это разрешение предоставляет ему доступ к данным нательных датчиков (например, пульсу, температуре, уровню кислорода в крови)."</string>
+ <string name="permlab_bodySensors_background" msgid="4912560779957760446">"Доступ к данным нательных датчиков, когда приложение работает в фоновом режиме"</string>
+ <string name="permdesc_bodySensors_background" product="default" msgid="8870726027557749417">"Когда приложение работает в фоновом режиме, это разрешение предоставляет ему доступ к данным нательных датчиков (например, пульсу, температуре, уровню кислорода в крови)."</string>
<string name="permlab_readCalendar" msgid="6408654259475396200">"Чтение мероприятий и данных"</string>
<string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Приложение может считывать, отправлять и сохранять информацию о мероприятиях в календаре планшета."</string>
<string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Приложение может считывать, отправлять и сохранять информацию о мероприятиях в календаре устройства Android TV."</string>
@@ -695,10 +691,8 @@
<string name="permdesc_readMediaAudio" msgid="5299772574434619399">"Приложение сможет считывать аудиофайлы из общего хранилища."</string>
<string name="permlab_readMediaVideo" msgid="7768003311260655007">"считывание видеофайлов из общего хранилища"</string>
<string name="permdesc_readMediaVideo" msgid="3846400073770403528">"Приложение сможет считывать видеофайлы из общего хранилища."</string>
- <!-- no translation found for permlab_readMediaImages (4057590631020986789) -->
- <skip />
- <!-- no translation found for permdesc_readMediaImages (5836219373138469259) -->
- <skip />
+ <string name="permlab_readMediaImages" msgid="4057590631020986789">"считывание изображений из общего хранилища"</string>
+ <string name="permdesc_readMediaImages" msgid="5836219373138469259">"Приложение сможет считывать изображения из общего хранилища."</string>
<string name="permlab_sdcardWrite" msgid="4863021819671416668">"Изменение или удаление данных на общем накопителе"</string>
<string name="permdesc_sdcardWrite" msgid="8376047679331387102">"Приложение сможет записывать данные на общий накопитель."</string>
<string name="permlab_use_sip" msgid="8250774565189337477">"Входящие и исходящие вызовы SIP"</string>
@@ -1459,12 +1453,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Разрешает приложению игнорировать ограничение на расход заряда батареи."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"Запрос информации обо всех пакетах"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Приложение сможет просматривать все установленные пакеты."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"доступ к AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Приложение сможет получать доступ к AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"доступ к AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Приложение сможет получать доступ к AdServices Attribution API."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"доступ к AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Приложение сможет получать доступ к AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Нажмите дважды для изменения масштаба"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Не удалось добавить виджет."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Выбрать"</string>
@@ -1947,6 +1935,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Приложение недоступно"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" сейчас недоступно."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недоступно: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Эта функция пока недоступна на устройстве <xliff:g id="DEVICE">%1$s</xliff:g>. Используйте Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Эта функция пока недоступна на устройстве <xliff:g id="DEVICE">%1$s</xliff:g>. Используйте планшет."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Эта функция пока недоступна на устройстве <xliff:g id="DEVICE">%1$s</xliff:g>. Используйте телефон."</string>
@@ -2042,7 +2032,7 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Разрешить приложению \"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>\" доступ ко всем журналам устройства?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Только в этот раз"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Запретить"</string>
- <!-- no translation found for log_access_confirmation_body (4483075525611652922) -->
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
<skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Больше не показывать"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Приложение \"<xliff:g id="APP_0">%1$s</xliff:g>\" запрашивает разрешение на показ фрагментов приложения \"<xliff:g id="APP_2">%2$s</xliff:g>\"."</string>
@@ -2277,7 +2267,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Приложение \"<xliff:g id="APP">%1$s</xliff:g>\" работает в фоновом режиме и расходует заряд батареи. Нажмите, чтобы узнать подробности."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Приложение \"<xliff:g id="APP">%1$s</xliff:g>\" работает в фоновом режиме уже длительное время. Нажмите, чтобы узнать подробности."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Проверить активные приложения"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Камера на этом устройстве недоступна."</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Язык системы"</string>
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 419e9f55aa20..e97fbfc96382 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"යෙදුමකට එම යෙදුම සඳහා බැටරි ප්‍රශස්තකරණ නොසලකා හැරීමට අවසර ඉල්ලීමට ඉඩ දෙයි."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"සියලු පැකේජ විමසන්න"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"ස්ථාපනය කර ඇති සියලු පැකේජ බැලීමට යෙදුමකට ඉඩ දෙයි."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API වෙත ප්‍රවේශ වන්න"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"AdServices Topics API වෙත ප්‍රවේශ වීමට යෙදුමකට ඉඩ දෙයි."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API වෙත ප්‍රවේශ වන්න"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"AdServices Attribution API වෙත ප්‍රවේශ වීමට යෙදුමකට ඉඩ දෙයි."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API වෙත ප්‍රවේශ වන්න"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"AdServices Custom Audiences API වෙත ප්‍රවේශ වීමට යෙදුමකට ඉඩ දෙයි."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"විශාලන පාලක සඳහා දෙවතාවක් තට්ටු කරන්න"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"විජටය එකතු කිරීමට නොහැකි විය."</string>
<string name="ime_action_go" msgid="5536744546326495436">"යන්න"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"යෙදුම ලබා ගත නොහැකිය"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> මේ දැන් ලබා ගත නොහැකිය."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> නොතිබේ"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"මේ අවස්ථාවේදී මෙයට ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> හි ප්‍රවේශ විය නොහැකිය. ඒ වෙනුවට ඔබගේ Android TV උපාංගයෙහි උත්සාහ කරන්න."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"මේ අවස්ථාවේදී මෙයට ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> හි ප්‍රවේශ විය නොහැකිය. ඒ වෙනුවට ඔබගේ ටැබ්ලටයෙහි උත්සාහ කරන්න."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"මේ අවස්ථාවේදී මෙයට ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> හි ප්‍රවේශ විය නොහැකිය. ඒ වෙනුවට ඔබගේ දුරකථනයෙහි උත්සාහ කරන්න."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> හට සියලු උපාංග ලොග ප්‍රවේශ වීමට ඉඩ දෙන්නද?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"මෙම වතාවේ පමණි"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"ඉඩ නොදෙන්න"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"උපාංග ලොග ඔබගේ උපාංගයේ සිදු වන දේ වාර්තා කරයි. ගැටලු සොයා ගැනීමට සහ විසඳීමට යෙදුම්වලට මෙම ලොග භාවිත කළ හැකිය.\n\nසමහර ලොගවල සංවේදී තොරතුරු අඩංගු විය හැකිය, එබැවින් ඔබ විශ්වාස කරන යෙදුම්වලට පමණක් සියලු උපාංග ලොග වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න. \n\nඔබ මෙම යෙදුමට සියලු උපාංග ලොග වෙත ප්‍රවේශ වීමට ඉඩ නොදෙන්නේ නම්, එයට තවමත් එහිම ලොග වෙත ප්‍රවේශ විය හැකි අතර ඔබගේ උපාංග නිෂ්පාදකයාට තවමත් ඔබගේ උපාංගයේ සමහර ලොග හෝ තොරතුරු වෙත ප්‍රවේශ විය හැකිය. තව දැන ගන්න"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"නැවත නොපෙන්වන්න"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> හට කොටස් <xliff:g id="APP_2">%2$s</xliff:g>ක් පෙන්වීමට අවශ්‍යයි"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"සංස්කරණය"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> පසුබිමේ ධාවනය වන අතර බැටරිය බැස යයි. සමාලෝචනය කිරීමට තට්ටු කරන්න."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> දිගු වේලාවක් පසුබිමේ ධාවනය වේ. සමාලෝචනය කිරීමට තට්ටු කරන්න."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"සක්‍රිය යෙදුම් පරීක්ෂා කරන්න"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"මෙම උපාංගයෙන් කැමරාවට ප්‍රවේශ විය නොහැකිය"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"පද්ධති භාෂාව"</string>
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index efe468bc9bdb..530f58c2c85f 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1453,12 +1453,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Umožňuje aplikácii požiadať o povolenie ignorovať optimalizácie výdrže batérie pre danú aplikáciu."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"dopytovať všetky balíky"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Povoľuje aplikácii čítať všetky nainštalované balíky."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"prístup k rozhraniu AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Umožňuje aplikácii prístup k rozhraniu AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"prístup k rozhraniam AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Umožňuje aplikácii prístup k rozhraniam AdServices Attribution API."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"prístup k rozhraniu AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Umožňuje aplikácii prístup k rozhraniu AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Dvojitým klepnutím môžete ovládať priblíženie"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Miniaplikáciu sa nepodarilo pridať."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Hľadať"</string>
@@ -1941,6 +1935,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikácia nie je dostupná"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> nie je teraz dostupná."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nie je k dispozícii"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte k tomuto obsahu prístup. Skúste namiesto toho použiť zariadenie Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte k tomuto obsahu prístup. Skúste namiesto toho použiť tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte k tomuto obsahu prístup. Skúste namiesto toho použiť telefón."</string>
@@ -2036,7 +2032,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Chcete povoliť aplikácii <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> prístup k všetkým denníkom zariadenia?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Iba tentokrát"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nepovoliť"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Denníky zariadenia zaznamenávajú, čo sa deje vo vašom zariadení. Aplikácie môžu pomocou týchto denníkov vyhľadávať a riešiť problémy.\n\nNiektoré denníky môžu obsahovať citlivé údaje, preto povoľte prístup k všetkým denníkom zariadenia iba dôveryhodným aplikáciám. \n\nAk tejto aplikácii nepovolíte prístup k všetkým denníkom zariadenia, stále bude mať prístup k vlastným denníkom a výrobca vášho zariadenia bude mať naďalej prístup k niektorým denníkom alebo informáciám vo vašom zariadení. Ďalšie informácie"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Už nezobrazovať"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> chce zobrazovať rezy z aplikácie <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Upraviť"</string>
@@ -2270,7 +2267,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Aplikácie <xliff:g id="APP">%1$s</xliff:g> je spustená na pozadí a vybíja batériu. Skontrolujte to klepnutím."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Aplikácia <xliff:g id="APP">%1$s</xliff:g> je dlhodobo spustená na pozadí. Skontrolujte to klepnutím."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Skontrolovať aktívne aplikácie"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"V tomto zariadení nemáte prístup ku kamere"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Jazyk systému"</string>
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 61d3cb60a1d8..b724c89ee495 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1453,12 +1453,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Aplikaciji dovoljuje, da vpraša za dovoljenje, ali naj prezre optimizacije baterije."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"poizvedovanje po vseh paketih"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Aplikaciji dovoli, da vidi vse nameščene pakete."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"dostop do API-ja AdServices Topics"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Aplikaciji omogoča dostop do API-ja AdServices Topics."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"dostop do API-jev AdServices Attribution"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Aplikaciji omogoča dostop do API-jev AdServices Attribution."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"dostop do API-ja AdServices Custom Audiences"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Aplikaciji omogoča dostop do API-ja AdServices Custom Audiences."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Tapnite dvakrat za nadzor povečave/pomanjšave"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Pripomočka ni bilo mogoče dodati."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Pojdi"</string>
@@ -1941,6 +1935,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija ni na voljo"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno ni na voljo."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"»<xliff:g id="ACTIVITY">%1$s</xliff:g>« ni na voljo"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"V napravi <xliff:g id="DEVICE">%1$s</xliff:g> trenutno ni mogoče dostopati do te vsebine. Poskusite z napravo Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"V napravi <xliff:g id="DEVICE">%1$s</xliff:g> trenutno ni mogoče dostopati do te vsebine. Poskusite s tabličnim računalnikom."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"V napravi <xliff:g id="DEVICE">%1$s</xliff:g> trenutno ni mogoče dostopati do te vsebine. Poskusite s telefonom."</string>
@@ -2036,7 +2032,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Ali aplikaciji <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> dovolite dostop do vseh dnevnikov naprave?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Samo tokrat"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne dovoli"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"V dnevnikih naprave se beleži dogajanje v napravi. Aplikacije lahko te dnevnike uporabijo za iskanje in odpravljanje težav.\n\nNekateri dnevniki morda vsebujejo občutljive podatke, zato dostop do vseh dnevnikov naprave omogočite le aplikacijam, ki jim zaupate. \n\nČe tej aplikaciji ne dovolite dostopa do vseh dnevnikov naprave, bo aplikacija kljub temu lahko dostopala do svojih dnevnikov, proizvajalec naprave pa do nekaterih dnevnikov ali podatkov v napravi. Več o tem"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikaži več"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi prikazati izreze aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
@@ -2270,7 +2267,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> se izvaja v ozadju in porablja energijo baterije. Dotaknite se za pregled."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> se dolgo časa izvaja v ozadju. Dotaknite se za pregled."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Preverite aktivne aplikacije"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"V tej napravi ni mogoče dostopati do fotoaparata."</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Sistemski jezik"</string>
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 46a6d7be5743..ac155e8462f4 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Lejon që një aplikacion të kërkojë leje për të shpërfillur optimizimet e baterisë për atë aplikacion."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"kërko të gjitha paketat"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Lejon një aplikacion të shikojë të gjitha paketat e instaluara."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"qasje në AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Lejon një aplikacion të ketë qasje në AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"qasje në AdServices Attribution APIs"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Lejon një aplikacion që të ketë qasje në AdServices Attribution APIs."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"qasje në AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Lejon një aplikacion të ketë qasje në AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Trokit dy herë për të kontrolluar zmadhimin"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Nuk mundi të shtonte miniaplikacion."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Shko"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacioni nuk ofrohet"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk ofrohet për momentin."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nuk ofrohet"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Qasja është e pamundur në <xliff:g id="DEVICE">%1$s</xliff:g> për momentin. Provoje në pajisjen Android TV më mirë."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Qasja është e pamundur në <xliff:g id="DEVICE">%1$s</xliff:g> për momentin. Provoje në tablet më mirë."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Qasja është e pamundur në <xliff:g id="DEVICE">%1$s</xliff:g> për momentin. Provoje në telefon më mirë."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Të lejohet që <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> të ketë qasje te të gjitha evidencat e pajisjes?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Vetëm këtë herë"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Mos lejo"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Evidencat e pajisjes regjistrojnë çfarë ndodh në pajisjen tënde. Aplikacionet mund t\'i përdorin këto evidenca për të gjetur dhe rregulluar problemet.\n\nDisa evidenca mund të përmbajnë informacione delikate, ndaj lejo vetëm aplikacionet që u beson të kenë qasje te të gjitha evidencat e pajisjes. \n\nNëse nuk e lejon këtë aplikacion që të ketë qasje te të gjitha evidencat e pajisjes, ai mund të ketë ende qasje tek evidencat e tij dhe prodhuesi i pajisjes sate mund të jetë ende në gjendje që të ketë qasje te disa evidenca ose informacione në pajisjen tënde. Mëso më shumë"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Mos e shfaq më"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> dëshiron të shfaqë pjesë të <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Modifiko"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> po ekzekutohet në sfond dhe po shkarkon baterinë. Trokit për ta shqyrtuar."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> po ekzekutohet në sfond për një kohe të gjatë. Trokit për ta shqyrtuar."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Kontrollo aplikacionet aktive"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Nuk mund të qasesh te kamera nga kjo pajisje"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Gjuha e sistemit"</string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index a49f9a5c7024..afe01d73b6bd 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1452,12 +1452,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Дозвољава апликацији да тражи дозволу за игнорисање оптимизација батерије за ту апликацију."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"слање упита за све пакете"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Дозвољава апликацији да види све инсталиране пакете."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"приступ API-ју за теме услуга огласа"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Дозвољава апликацији да приступа API-ју за теме услуга огласа."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"приступ API-јима за приписивање услуга огласа"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Дозвољава апликацији да приступа API-јима за дистрибуцију услуга огласа."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"приступ API-ју за прилагођене публике услуга огласа"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Дозвољава апликацији да приступа API-ју за прилагођене публике услуга огласа."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Додирните двапут за контролу зумирања"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Није могуће додати виџет."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Иди"</string>
@@ -1940,6 +1934,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Апликација није доступна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> тренутно није доступна."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – није доступно"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Потребна је дозвола"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Овој апликацији тренутно не може да се приступи са уређаја <xliff:g id="DEVICE">%1$s</xliff:g>. Пробајте на Android TV уређају."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Овој апликацији тренутно не може да се приступи са уређаја <xliff:g id="DEVICE">%1$s</xliff:g>. Пробајте на таблету."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Овој апликацији тренутно не може да се приступи са уређаја <xliff:g id="DEVICE">%1$s</xliff:g>. Пробајте на телефону."</string>
@@ -2035,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Желите да дозволите апликацији <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> да приступа свим евиденцијама уређаја?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Само овај пут"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дозволи"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Евиденције уређаја региструју шта се дешава на уређају. Апликације могу да користе те евиденције да би пронашле и решиле проблеме.\n\nНеке евиденције могу да садрже осетљиве информације, па приступ свим евиденцијама уређаја треба да дозвољавате само апликацијама у које имате поверења. \n\nАко не дозволите овој апликацији да приступа свим евиденцијама уређаја, она и даље може да приступа сопственим евиденцијама, а произвођач уређаја ће можда и даље моћи да приступа неким евиденцијама или информацијама на уређају. Сазнајте више"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Не приказуј поново"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Апликација <xliff:g id="APP_0">%1$s</xliff:g> жели да приказује исечке из апликације <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Измени"</string>
@@ -2269,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Апликација <xliff:g id="APP">%1$s</xliff:g> троши батерију у позадини. Додирните да бисте прегледали."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Апликација <xliff:g id="APP">%1$s</xliff:g> је предуго покренута у позадини. Додирните да бисте прегледали."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Проверите активне апликације"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Не можете да приступите камери са овог уређаја"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Језик система"</string>
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index a6cad240b068..888fdd937b64 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Appen får be om tillstånd att ignorera batterioptimering."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"fråga alla paket"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Tillåter att en app ser alla installerade paket."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"få åtkomst till AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Tillåter att en app får åtkomst till AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"få åtkomst till AdServices Attribution API:er"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Tillåter att en app får åtkomst till AdServices Attribution API:er."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"få åtkomst till AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Tillåter att en app får åtkomst till AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Peka två gånger för zoomkontroll"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Det gick inte att lägga till widgeten."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Kör"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Appen är inte tillgänglig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> är inte tillgängligt just nu."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> är inte tillgänglig"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Det går inte att streama detta till <xliff:g id="DEVICE">%1$s</xliff:g> för närvarande. Testa med Android TV-enheten i stället."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Det går inte att streama detta till <xliff:g id="DEVICE">%1$s</xliff:g> för närvarande. Testa med surfplattan i stället."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Det går inte att streama detta till <xliff:g id="DEVICE">%1$s</xliff:g> för närvarande. Testa med telefonen i stället."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Vill du tillåta att <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> får åtkomst till alla enhetsloggar?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Bara den här gången"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Tillåt inte"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Enhetsloggar registrerar vad som händer på enheten. Appar kan använda dessa loggar för att hitta och åtgärda problem.\n\nVissa loggar kan innehålla känsliga uppgifter, så du ska bara tillåta att appar du litar på får åtkomst till alla enhetsloggar. \n\nOm du inte ger appen åtkomst till alla enhetsloggar har den ändå åtkomst till sina egna loggar, och enhetstillverkare kan fortfarande få åtkomst till vissa loggar eller viss information på enheten. Läs mer"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Visa inte igen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vill kunna visa bitar av <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Redigera"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> körs i bakgrunden så att batteriet tar slut fortare. Tryck för att granska."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> har körts i bakgrunden under lång tid. Tryck för att granska."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Kontrollera aktiva appar"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Det går inte att komma åt kameran från den här enheten"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Systemets språkinställning"</string>
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 1d7f1824086a..cca9d09bf902 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Huruhusu programu kuomba ruhusa ya kupuuza uimarishaji wa betri katika programu yako."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"kutuma hoja kwa vifurushi vyote"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Huruhusu programu kuona vifurushi vyote vilivyosakinishwa."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"fikia API za Mada za AdServices"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Inaruhusu programu kufikia API za Mada za AdServices."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"fikia API za Maelezo za AdServices"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Inaruhusu programu kufikia API za Maelezo za AdServices."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"fikia API za Hadhira Maalumu za AdServices."</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Inaruhusu programu kufikia API za Hadhira Maalumu za AdServices."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Gusa mara mbili kwa udhibiti wa kuza"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Haikuweza kuongeza wijeti."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Nenda"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Programu haipatikani"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> haipatikani hivi sasa."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> haipatikani"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Programu hii haiwezi kufikiwa kwenye <xliff:g id="DEVICE">%1$s</xliff:g> kwa muda huu. Badala yake jaribu kwenye kifaa chako cha Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Programu hii haiwezi kufikiwa kwenye <xliff:g id="DEVICE">%1$s</xliff:g> kwa muda huu. Badala yake jaribu kwenye kompyuta kibao yako."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Programu hii haiwezi kufikiwa kwenye <xliff:g id="DEVICE">%1$s</xliff:g> kwa muda huu. Badala yake jaribu kwenye simu yako."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Ungependa kuruhusu <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ifikie kumbukumbu zote za kifaa?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Mara hii pekee"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Usiruhusu"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Kumbukumbu za kifaa hurekodi kinachofanyika kwenye kifaa chako. Programu zinaweza kutumia kumbukumbu hizi ili kutambua na kurekebisha hitilafu.\n\nBaadhi ya kumbukumbu huweza kuwa na taarifa nyeti, hivyo ruhusu tu programu unazoziamini kufikia kumbukumbu zote za kifaa. \n\nIwapo hutaruhusu programu hii ifikie kumbukumbu zote za kifaa, bado inaweza kufikia kumbukumbu zake yenyewe na mtengenezaji wa kifaa chako bado anaweza kufikia baadhi ya kumbukumbu au taarifa zilizopo kwenye kifaa chako. Pata maelezo zaidi"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Usionyeshe tena"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> inataka kuonyesha vipengee <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Badilisha"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> inatumika chinichini na kumaliza nishati ya betri. Gusa ili ukague."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> inatumika chinichini kwa muda mrefu. Gusa ili ukague."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Angalia programu zinazotumika"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Haiwezi kufikia kamera kwenye kifaa hiki"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Lugha ya mfumo"</string>
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index f13d17777220..14ded62c26d5 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"பயன்பாட்டிற்கான பேட்டரி மேம்படுத்தல்களைப் புறக்கணிப்பதற்கான அனுமதியைக் கோர, ஆப்ஸை அனுமதிக்கும்."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"அனைத்துப் பேக்கேஜ்களையும் பார்க்க அனுமதித்தல்"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"நிறுவப்பட்டுள்ள அனைத்துப் பேக்கேஜ்களையும் பார்ப்பதற்கு ஆப்ஸை அனுமதிக்கும்."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics APIயை அணுகுதல்"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"AdServices Topics APIயை அணுக ஆப்ஸை அனுமதிக்கும்."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution APIகளை அணுகுதல்"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"AdServices Attribution APIகளை அணுக ஆப்ஸை அனுமதிக்கும்."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences APIயை அணுகுதல்"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"AdServices Custom Audiences APIயை அணுக ஆப்ஸை அனுமதிக்கும்."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"அளவை மாற்றுவதற்கான கட்டுப்பாட்டிற்கு, இருமுறை தட்டவும்"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"விட்ஜெட்டைச் சேர்க்க முடியவில்லை."</string>
<string name="ime_action_go" msgid="5536744546326495436">"செல்"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"இந்த ஆப்ஸ் இப்போது கிடைப்பதில்லை"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் இப்போது கிடைப்பதில்லை."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> இல்லை"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"தற்போது உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்தில் இதை அணுக முடியாது. அதற்குப் பதிலாக Android TV சாதனத்தில் பயன்படுத்திப் பாருங்கள்."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"தற்போது உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்தில் இதை அணுக முடியாது. அதற்குப் பதிலாக உங்கள் டேப்லெட்டில் பயன்படுத்திப் பாருங்கள்."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"தற்போது உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்தில் இதை அணுக முடியாது. அதற்குப் பதிலாக உங்கள் மொபைலில் பயன்படுத்திப் பாருங்கள்."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"சாதனப் பதிவுகள் அனைத்தையும் <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> அணுக அனுமதிக்கவா?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"இப்போது மட்டும்"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"அனுமதிக்க வேண்டாம்"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"உங்கள் சாதனத்தில் நடப்பவற்றைச் சாதனப் பதிவுகள் ரெக்கார்டு செய்யும். சிக்கல்களைக் கண்டறிந்து சரிசெய்ய ஆப்ஸ் இந்தப் பதிவுகளைப் பயன்படுத்தலாம்.\n\nபாதுகாக்கப்பட வேண்டிய தகவல்கள் சில பதிவுகளில் இருக்கக்கூடும் என்பதால் சாதனப் பதிவுகள் அனைத்தையும் அணுக நீங்கள் நம்பும் ஆப்ஸை மட்டுமே அனுமதிக்கவும். \n\nசாதனப் பதிவுகள் அனைத்தையும் அணுக இந்த ஆப்ஸை நீங்கள் அனுமதிக்கவில்லை என்றாலும் அதற்குச் சொந்தமான பதிவுகளைத் தொடர்ந்து அதனால் அணுக முடியும். மேலும் உங்கள் சாதன உற்பத்தியாளர் உங்கள் சாதனத்திலுள்ள சில பதிவுகளையோ தகவல்களையோ தொடர்ந்து அணுகக்கூடும். மேலும் அறிக"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"மீண்டும் காட்டாதே"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_2">%2$s</xliff:g> ஆப்ஸின் விழிப்பூட்டல்களைக் காண்பிக்க, <xliff:g id="APP_0">%1$s</xliff:g> அனுமதி கேட்கிறது"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"திருத்து"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ஆப்ஸ் பின்னணியில் இயங்குவதுடன் பேட்டரியை அதிகமாகப் பயன்படுத்துகிறது. பார்க்க தட்டவும்."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ஆப்ஸ் நீண்ட நேரமாகப் பின்னணியில் இயங்குகிறது. பார்க்க தட்டவும்."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"செயலிலுள்ள ஆப்ஸைப் பாருங்கள்"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"இந்தச் சாதனத்திலிருந்து கேமராவை அணுக முடியவில்லை"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"சிஸ்டம் மொழி"</string>
</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 30209b1a4df1..0fa7a9ff2209 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"ఆ యాప్ కోసం బ్యాటరీ అనుకూలీకరణలు విస్మరించేలా అనుమతి కోరడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"అన్ని ప్యాకేజీలను క్వెరీ చేయండి"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"ఇన్‌స్టాల్ చేసిన అన్ని ప్యాకేజీలను చూడటానికి యాప్‌ను అనుమతించండి."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices టాపిక్స్ APIని యాక్సెస్ చేయండి"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"AdServices టాపిక్స్ APIని యాక్సెస్ చేయడానికి అప్లికేషన్‌ను అనుమతిస్తుంది."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices అట్రిబ్యూషన్ APIలను యాక్సెస్ చేయండి"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"AdServices అట్రిబ్యూషన్ APIలను యాక్సెస్ చేయడానికి అప్లికేషన్‌ను అనుమతిస్తుంది."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices అనుకూల ప్రేక్షకుల APIని యాక్సెస్ చేయండి"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"AdServices అనుకూల ప్రేక్షకుల APIని యాక్సెస్ చేయడానికి అప్లికేషన్‌ను అనుమతిస్తుంది."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"జూమ్ నియంత్రణ కోసం రెండుసార్లు నొక్కండి"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"విడ్జెట్‌ను జోడించడం సాధ్యపడలేదు."</string>
<string name="ime_action_go" msgid="5536744546326495436">"వెళ్లు"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"యాప్ అందుబాటులో లేదు"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రస్తుతం అందుబాటులో లేదు."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> అందుబాటులో లేదు"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"అనుమతి అవసరం"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ఈ సమయంలో మీ <xliff:g id="DEVICE">%1$s</xliff:g>లో దీన్ని యాక్సెస్ చేయడం సాధ్యపడదు. బదులుగా మీ Android TV పరికరంలో ట్రై చేయండి."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ఈ సమయంలో మీ <xliff:g id="DEVICE">%1$s</xliff:g>లో దీన్ని యాక్సెస్ చేయడం సాధ్యపడదు. బదులుగా మీ టాబ్లెట్‌లో ట్రై చేయండి."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ఈ సమయంలో మీ <xliff:g id="DEVICE">%1$s</xliff:g>లో దీన్ని యాక్సెస్ చేయడం సాధ్యపడదు. బదులుగా మీ ఫోన్‌లో ట్రై చేయండి."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"అన్ని పరికర లాగ్‌లను యాక్సెస్ చేయడానికి <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>‌ను అనుమతించాలా?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"ఈ ఒక్కసారి మాత్రమే"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"అనుమతించవద్దు"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"మీ పరికరంలో జరిగే దాన్ని పరికర లాగ్‌లు రికార్డ్ చేస్తాయి. సమస్యలను కనుగొని, పరిష్కరించడానికి యాప్‌లు ఈ లాగ్‌లను ఉపయోగిస్తాయి.\n\nకొన్ని లాగ్‌లలో గోప్యమైన సమాచారం ఉండవచ్చు, కాబట్టి మీరు విశ్వసించే యాప్‌లను మాత్రమే అన్ని పరికర లాగ్‌లను యాక్సెస్ చేయడానికి అనుమతించండి. \n\nఅన్ని పరికర లాగ్‌లను యాక్సెస్ చేయడానికి మీరు ఈ యాప్‌ను అనుమతించకపోతే, అది తన స్వంత లాగ్‌లను యాక్సెస్ చేయగలదు, మీ పరికర తయారీదారు ఇప్పటికీ మీ పరికరంలో కొన్ని లాగ్‌లు లేదా సమాచారాన్ని యాక్సెస్ చేయగలరు. మరింత తెలుసుకోండి"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"మళ్లీ చూపవద్దు"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> స్లైస్‌లను చూపించాలనుకుంటోంది"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ఎడిట్ చేయండి"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> బ్యాక్‌గ్రౌండ్‌లో రన్ అవుతోంది, బ్యాటరీని ఎక్కువగా వాడుతోంది. రివ్యూ చేయడానికి ట్యాప్ చేయండి."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> చాలా సమయం నుండి బ్యాక్‌గ్రౌండ్‌లో రన్ అవుతోంది. రివ్యూ చేయడానికి ట్యాప్ చేయండి."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"యాక్టివ్‌గా ఉన్న యాప్‌లను చెక్ చేయండి"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"ఈ పరికరం నుండి కెమెరాను యాక్సెస్ చేయడం సాధ్యపడదు"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"సిస్టమ్ భాష"</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 51b6c8d810bc..5ab27266700a 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"อนุญาตให้แอปขอสิทธิ์เพิกเฉยต่อการเพิ่มประสิทธิภาพแบตเตอรี่สำหรับแอปนั้น"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"ค้นหาแพ็กเกจทั้งหมด"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"อนุญาตให้แอปดูแพ็กเกจที่ติดตั้งไว้ทั้งหมด"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"เข้าถึง AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"อนุญาตให้แอปพลิเคชันเข้าถึง AdServices Topics API"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"เข้าถึง AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"อนุญาตให้แอปพลิเคชันเข้าถึง AdServices Attribution API"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"เข้าถึง AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"อนุญาตให้แอปพลิเคชันเข้าถึง AdServices Custom Audiences API"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"แตะสองครั้งเพื่อควบคุมการซูม"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"ไม่สามารถเพิ่มวิดเจ็ต"</string>
<string name="ime_action_go" msgid="5536744546326495436">"ไป"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"แอปไม่พร้อมใช้งาน"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่พร้อมใช้งานในขณะนี้"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ไม่พร้อมใช้งาน"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"ต้องการสิทธิ์"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"เข้าถึงแอปนี้ใน <xliff:g id="DEVICE">%1$s</xliff:g> ของคุณไม่ได้ในขณะนี้ โปรดลองเข้าถึงในอุปกรณ์ Android TV แทน"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"เข้าถึงแอปนี้ใน <xliff:g id="DEVICE">%1$s</xliff:g> ของคุณไม่ได้ในขณะนี้ โปรดลองเข้าถึงในแท็บเล็ตแทน"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"เข้าถึงแอปนี้ใน <xliff:g id="DEVICE">%1$s</xliff:g> ของคุณไม่ได้ในขณะนี้ โปรดลองเข้าถึงในโทรศัพท์แทน"</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"อนุญาตให้ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> เข้าถึงบันทึกทั้งหมดของอุปกรณ์ใช่ไหม"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"เฉพาะครั้งนี้"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"ไม่อนุญาต"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"บันทึกของอุปกรณ์เก็บข้อมูลสิ่งที่เกิดขึ้นในอุปกรณ์ แอปสามารถใช้บันทึกนี้เพื่อค้นหาและแก้ไขปัญหา\n\nบันทึกบางรายการอาจมีข้อมูลที่ละเอียดอ่อน ดังนั้นคุณควรอนุญาตเฉพาะแอปที่เชื่อถือได้ให้เข้าถึงบันทึกทั้งหมดของอุปกรณ์ \n\nหากคุณไม่อนุญาตให้แอปนี้เข้าถึงบันทึกทั้งหมดของอุปกรณ์ แอปจะยังเข้าถึงบันทึกของตัวเองได้อยู่ และผู้ผลิตอุปกรณ์อาจยังเข้าถึงบันทึกหรือข้อมูลบางรายการในอุปกรณ์ของคุณได้ ดูข้อมูลเพิ่มเติม"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"ไม่ต้องแสดงอีก"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ต้องการแสดงส่วนต่างๆ ของ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"แก้ไข"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> กำลังทำงานอยู่ในเบื้องหลังและทำให้เปลืองแบตเตอรี่ แตะเพื่อตรวจสอบ"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ทำงานอยู่ในเบื้องหลังเป็นเวลานาน แตะเพื่อตรวจสอบ"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ตรวจสอบแอปที่ใช้งานอยู่"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"เข้าถึงกล้องจากอุปกรณ์นี้ไม่ได้"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"ภาษาของระบบ"</string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 6b1025aee627..aee994b0bef0 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Pinapayagang humingi ng pahintulot ang isang app na balewalain ang mga pag-optimize ng baterya para sa app na iyon."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"i-query ang lahat ng package"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Nagbibigay-daan sa isang app na makita ang lahat ng naka-install na package."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"i-access ang AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Nagbibigay-daan sa isang application na i-access ang AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"i-access ang mga AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Nagbibigay-daan sa isang application na i-access ang mga AdServices Attribution API."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"i-access ang AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Nagbibigay-daan sa isang application na i-access ang AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Tapikin ng dalawang beses para sa pagkontrol ng zoom"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Hindi maidagdag ang widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Pumunta"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Hindi available ang app"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Hindi available sa ngayon ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Hindi available ang <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Kailangan ng pahintulot"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Hindi ito maa-access sa iyong <xliff:g id="DEVICE">%1$s</xliff:g> sa ngayon. Subukan na lang sa iyong Android TV device."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Hindi ito maa-access sa iyong <xliff:g id="DEVICE">%1$s</xliff:g> sa ngayon. Subukan na lang sa iyong tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Hindi ito maa-access sa iyong <xliff:g id="DEVICE">%1$s</xliff:g> sa ngayon. Subukan na lang sa iyong telepono."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Payagan ang <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> na i-access ang lahat ng log ng device?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Ngayon lang"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Huwag payagan"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Nire-record ng mga log ng device kung ano ang nangyayari sa iyong device. Magagamit ng mga app ang mga log na ito para maghanap at mag-ayos ng mga isyu.\n\nPosibleng maglaman ang ilang log ng sensitibong impormasyon, kaya ang mga app lang na pinagkakatiwalaan mo ang payagang maka-access sa lahat ng log ng device. \n\nKung hindi mo papayagan ang app na ito na i-access ang lahat ng log ng device, maa-access pa rin nito ang mga sarili nitong log, at posible pa ring ma-access ng manufacturer ng iyong device ang ilang log o impormasyon sa device mo. Matuto pa"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Huwag ipakita ulit"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Gustong ipakita ng <xliff:g id="APP_0">%1$s</xliff:g> ang mga slice ng <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"I-edit"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Gumagana ang <xliff:g id="APP">%1$s</xliff:g> sa background at gumagamit ito ng baterya I-tap para suriin."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Napakatagal nang gumagana ang <xliff:g id="APP">%1$s</xliff:g> sa background. I-tap para suriin."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Tingnan ang mga aktibong app"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Hindi ma-access ang camera mula sa device na ito"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Wika ng system"</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 1e0cff506e92..b3624f37329d 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Bir uygulamanın, kendisi için pil optimizasyonlarını göz ardı etme izni istemesine olanak sağlar."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"tüm paketleri sorgulama"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Uygulamaya tüm yüklü paketleri görme izni verir."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API\'sine eriş"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Uygulamanın AdServices Topics API\'sine erişmesine izin verir."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API\'lerine eriş"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Uygulamanın AdServices Attribution API\'lerine erişmesine izin verir."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API\'sine eriş"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Uygulamanın AdServices Custom Audiences API\'sine erişmesine izin verir."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Zum denetimi için iki kez dokun"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Widget eklenemedi."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Git"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Uygulama kullanılamıyor"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması şu anda kullanılamıyor."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> kullanılamıyor"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Bu uygulamaya şu anda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan erişilemiyor. Bunun yerine Android TV cihazınızı kullanmayı deneyin."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Bu uygulamaya şu anda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan erişilemiyor. Bunun yerine tabletinizi kullanmayı deneyin."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Bu uygulamaya şu anda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan erişilemiyor. Bunun yerine telefonunuzu kullanmayı deneyin."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> uygulamasının tüm cihaz günlüklerine erişmesine izin verilsin mi?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Yalnız bu sefer"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"İzin verme"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Cihaz günlükleri, cihazınızda olanları kaydeder. Uygulamalar, sorunları bulup düzeltmek için bu günlükleri kullanabilir.\n\nBazı günlükler hassas bilgiler içerebileceği için yalnızca güvendiğiniz uygulamaların tüm cihaz günlüklerine erişmesine izin verin. \n\nBu uygulamanın tüm cihaz günlüklerine erişmesine izin vermeseniz de kendi günlüklerine erişmeye devam edebilir. Ayrıca, cihaz üreticiniz de cihazınızdaki bazı günlüklere veya bilgilere erişmeye devam edebilir. Daha fazla bilgi"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Bir daha gösterme"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> uygulaması, <xliff:g id="APP_2">%2$s</xliff:g> dilimlerini göstermek istiyor"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Düzenle"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> arka planda çalışıyor ve pil tüketiyor. İncelemek için dokunun."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> uzun süredir arka planda çalışıyor. İncelemek için dokunun."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Etkin uygulamaları kontrol edin"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Bu cihazdan kameraya erişilemiyor"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Sistem dili"</string>
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 997bf472156f..56a53ea202f5 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1453,12 +1453,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Додаток зможе запитувати дозвіл ігнорувати оптимізацію використання заряду акумулятора."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"подавати запити на всі пакети"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Дозволяє додатку переглядати всі встановлені пакети."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"надавати доступ до AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Надає додатку доступ до AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"надавати доступ до інтерфейсів API AdServices Attribution"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Надає додатку доступ до інтерфейсів API AdServices Attribution."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"надавати доступ до AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Надає додатку доступ до AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Двічі натис. для кер. масшт."</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Не вдалося додати віджет."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Йти"</string>
@@ -1941,6 +1935,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Додаток недоступний"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зараз недоступний."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недоступно: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Цей додаток зараз недоступний на вашому <xliff:g id="DEVICE">%1$s</xliff:g>. Спробуйте натомість скористатися пристроєм Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Цей додаток зараз недоступний на вашому <xliff:g id="DEVICE">%1$s</xliff:g>. Спробуйте натомість скористатися планшетом."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Цей додаток зараз недоступний на вашому <xliff:g id="DEVICE">%1$s</xliff:g>. Спробуйте натомість скористатися телефоном."</string>
@@ -2036,7 +2032,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Надати додатку <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> доступ до всіх журналів пристрою?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Лише цього разу"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дозволяти"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"У журналах пристрою реєструється все, що відбувається на ньому. За допомогою цих журналів додатки можуть виявляти й усувати проблеми.\n\nДеякі журнали можуть містити конфіденційні дані, тому надавати доступ до всіх журналів пристрою слід лише надійним додаткам. \n\nЯкщо додаток не має доступу до всіх журналів пристрою, він усе одно може використовувати власні журнали, а виробник вашого пристрою – деякі журнали чи інформацію на ньому. Докладніше"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Більше не показувати"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> хоче показати фрагменти додатка <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Редагувати"</string>
@@ -2270,7 +2267,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Додаток <xliff:g id="APP">%1$s</xliff:g> працює у фоновому режимі та розряджає акумулятор. Натисніть, щоб переглянути."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Додаток <xliff:g id="APP">%1$s</xliff:g> довго працює у фоновому режимі. Натисніть, щоб переглянути."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Перевірте активні додатки"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Не вдається отримати доступ до камери через цей пристрій"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Мова системи"</string>
</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 2770f89ee95c..a9f21f0bf1df 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"اس ایپ کیلئے ایک ایپ کو بیٹری کی کارکردگی بہتر بنانے کو نظر انداز کرنے کی اجازت دیں۔"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"سبھی پیکیجز سے متعلق استفسار کریں"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"ایپ کو سبھی انسٹال کردہ پیکیجز دیکھنے کی اجازت دیتا ہے۔"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"‏AdServices Topics API تک رسائی حاصل کریں"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"‏کسی ایپلیکیشن کو AdServices Topics API تک رسائی کی اجازت دیتا ہے۔"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"‏AdServices Attribution APIs تک رسائی حاصل کریں"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"‏کسی ایپلیکیشن کو AdServices Attribution APIs تک رسائی کی اجازت دیتا ہے۔"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"‏AdServices Custom Audiences API تک رسائی حاصل کریں"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"‏کسی ایپلیکیشن کو AdServices Custom Audiences API تک رسائی کی اجازت دیتا ہے۔"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"زوم کنٹرول کیلئے دوبار تھپتھپائیں"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"ویجٹس کو شامل نہیں کرسکا۔"</string>
<string name="ime_action_go" msgid="5536744546326495436">"جائیں"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ایپ دستیاب نہیں ہے"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ابھی دستیاب نہیں ہے۔"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> دستیاب نہیں ہے"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"‏اس وقت آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> پر اس تک رسائی نہیں مل سکتی۔ اس کے بجائے اپنے Android TV آلے پر کوشش کریں۔"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"اس وقت آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> پر اس تک رسائی نہیں مل سکتی۔ اس کے بجائے اپنے ٹیبلیٹ پر کوشش کریں۔"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"اس وقت آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> پر اس تک رسائی نہیں مل سکتی۔ اس کے بجائے اپنے فون پر کوشش کریں۔"</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> کو آلے کے تمام لاگز تک رسائی کی اجازت دیں؟"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"صرف اس وقت"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"اجازت نہ دیں"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"آپ کے آلے پر جو ہوتا ہے آلے کے لاگز اسے ریکارڈ کر لیتے ہیں۔ ایپس ان لاگز کا استعمال مسائل کو تلاش کرنے اور ان کو حل کرنے کے لیے کر سکتی ہیں۔\n\nکچھ لاگز میں حساس معلومات شامل ہو سکتی ہیں، اس لیے صرف اپنے بھروسے مند ایپس کو ہی آلے کے تمام لاگز تک رسائی کی اجازت دیں۔ \n\nاگر آپ اس ایپ کو آلے کے تمام لاگز تک رسائی کی اجازت نہیں دیتے ہیں، پھر بھی اسے اپنی خود کی لاگز تک رسائی حاصل ہو سکتی ہے اور آپ کے آلے کا مینوفیکچرر اب بھی آپ کے آلے پر موجود کچھ لاگز یا معلومات تک رسائی حاصل کر سکتا ہے۔ مزید جانیں"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"دوبارہ نہ دکھائیں"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> کے سلائسز دکھانا چاہتی ہے"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ترمیم کریں"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"‫<xliff:g id="APP">%1$s</xliff:g> پس منظر میں چل رہی ہے اور بیٹری ختم ہو رہی ہے۔ جائزے کے لیے تھپتھپائیں۔"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> کافی وقت سے پس منظر میں چل رہی ہے۔ جائزے کے لیے تھپتھپائیں۔"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"فعال ایپس چیک کریں"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"اس آلہ سے کیمرا تک رسائی حاصل نہیں کر سکتے"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"سسٹم کی زبان"</string>
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index f823fc693d0c..929d9d35c22b 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Ilovaga batareya quvvatidan xohlagancha foydalanish uchun ruxsat so‘rashga imkon beradi."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"barcha paketlarni chiqarish"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Ilova oʻrnatilgan barcha paketlarni koʻrishiga ruxsat beradi"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"AdServices Topics API taʼminotiga ruxsat"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Ilovaga AdServices Topics API taʼminotiga kirishga ruxsat beradi."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"AdServices Attribution API taʼminotiga ruxsat"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Ilovaga AdServices Attribution API taʼminotlariga kirishga ruxsat beradi."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"AdServices Custom Audiences API taʼminotiga ruxsat"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Ilovaga AdServices Custom Audiences API taʼminotiga kirishga ruxsat beradi."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Ko‘lamini o‘zgartirish uchun ikki marta bosing"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Vidjet qo‘shilmadi."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Tanlash"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Ilova ishlamayapti"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Ayni vaqtda <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi ishlamayapti."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> kanali ish faoliyatida emas"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Ayni vaqtda bu translatsiya <xliff:g id="DEVICE">%1$s</xliff:g> qurilmangizda ishlamaydi. Android TV qurilmasi orqali urinib koʻring."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Ayni vaqtda bu translatsiya <xliff:g id="DEVICE">%1$s</xliff:g> qurilmangizda ishlamaydi. Planshet orqali urinib koʻring."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Ayni vaqtda bu translatsiya <xliff:g id="DEVICE">%1$s</xliff:g> qurilmangizda ishlamaydi. Telefon orqali urininb koʻring."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ilovasiga qurilmadagi barcha jurnal qaydlariga ruxsat berilsinmi?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Faqat shu safar"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Rad etish"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Qurilma jurnaliga qurilma bilan yuz bergan hodisalar qaydlari yoziladi. Ilovalar bu jurnal qaydlari yordamida muammolarni topishi va bartaraf qilishi mumkin.\n\nAyrim jurnal qaydlarida maxfiy axborotlar yozilishi mumkin, shu sababli qurilmadagi barcha jurnal qaydlariga ruxsatni faqat ishonchli ilovalarga bering. \n\nBu ilovaga qurilmadagi barcha jurnal qaydlariga ruxsat berilmasa ham, u oʻzining jurnalini, shuningdek, qurilma ishlab chiqaruvchisi ham ayrim jurnallar yoki qurilma haqidagi axborotlarni ochishi mumkin. Batafsil"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Boshqa chiqmasin"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ilovasi <xliff:g id="APP_2">%2$s</xliff:g> ilovasidan fragmentlar ko‘rsatish uchun ruxsat so‘ramoqda"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Tahrirlash"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> fonda ishlamoqda va batareyani tugatmoqda. Tekshirish uchun bosing."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> uzoq vaqt orqa fonda ishlamoqda. Tekshirish uchun bosing."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Faol ilovalarni tekshiring"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Kamera bu qurilma orqali ochilmadi"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Tizim tili"</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 772a2249f23a..e22126d6b851 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Cho phép ứng dụng hỏi quyền để bỏ qua tối ưu hóa pin cho ứng dụng đó."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"truy vấn tất cả các gói"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Cho phép một ứng dụng xem tất cả các gói đã cài đặt."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"truy cập vào AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Cho phép ứng dụng truy cập vào AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"truy cập vào các AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Cho phép ứng dụng truy cập vào các AdServices Attribution API."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"truy cập vào AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Cho phép ứng dụng truy cập vào AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Nhấn hai lần để kiểm soát thu phóng"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Không thể thêm tiện ích."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Đến"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Ứng dụng này không dùng được"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hiện không dùng được."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Không hỗ trợ <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Hiện tại, bạn không thể truy cập vào ứng dụng này trên <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy thử trên thiết bị Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Hiện tại, bạn không thể truy cập vào ứng dụng này trên <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy thử trên máy tính bảng."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Hiện tại, bạn không thể truy cập vào ứng dụng này trên <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy thử trên điện thoại."</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Cho phép <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> truy cập vào tất cả các nhật ký thiết bị?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Chỉ lần này"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Không cho phép"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Nhật ký thiết bị ghi lại những hoạt động diễn ra trên thiết bị. Các ứng dụng có thể dùng nhật ký này để tìm và khắc phục sự cố.\n\nMột số nhật ký có thể chứa thông tin nhạy cảm, vì vậy, bạn chỉ nên cấp quyền truy cập vào tất cả các nhật ký thiết bị cho những ứng dụng mà mình tin cậy. \n\nNếu bạn không cho phép ứng dụng này truy cập vào tất cả các nhật ký thiết bị, ứng dụng vẫn có thể truy cập vào nhật ký của chính nó. Ngoài ra, nhà sản xuất thiết bị cũng có thể truy cập vào một số nhật ký hoặc thông tin trên thiết bị của bạn. Tìm hiểu thêm"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Không hiện lại"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> muốn hiển thị các lát của <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Chỉnh sửa"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> đang chạy trong nền và làm tiêu hao pin. Nhấn để xem."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> đang chạy trong nền trong thời gian dài. Nhấn để xem lại."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Xem các ứng dụng đang hoạt động"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Không sử dụng được máy ảnh trên thiết bị này"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Ngôn ngữ hệ thống"</string>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index b88a05d3d584..9053195d09c0 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"允许应用请求相应的权限,以便忽略针对该应用的电池优化。"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"查询所有软件包"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"允许应用查看所有已安装的软件包。"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"访问 AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"允许应用访问 AdServices Topics API。"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"访问 AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"允许应用访问 AdServices Attribution API。"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"访问 AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"允许应用访问 AdServices Custom Audiences API。"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"双击可以进行缩放控制"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"无法添加微件。"</string>
<string name="ime_action_go" msgid="5536744546326495436">"开始"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"应用无法使用"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g>目前无法使用。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>不可用"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"目前无法在您的<xliff:g id="DEVICE">%1$s</xliff:g>上访问此内容。您可以尝试在 Android TV 设备上访问。"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"目前无法在您的<xliff:g id="DEVICE">%1$s</xliff:g>上访问此内容。您可以尝试在平板电脑上访问。"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"目前无法在您的<xliff:g id="DEVICE">%1$s</xliff:g>上访问此内容。您可以尝试在手机上访问。"</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"允许“<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>”访问所有设备日志吗?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"仅限这一次"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"不允许"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"设备日志会记录设备上发生的活动。应用可以使用这些日志查找和修复问题。\n\n部分日志可能包含敏感信息,因此请仅允许您信任的应用访问所有设备日志。\n\n如果您不授予此应用访问所有设备日志的权限,那么它仍然可以访问自己的日志,并且您的设备制造商可能仍然能够访问您设备上的部分日志或信息。了解详情"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"不再显示"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"“<xliff:g id="APP_0">%1$s</xliff:g>”想要显示“<xliff:g id="APP_2">%2$s</xliff:g>”图块"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"编辑"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"“<xliff:g id="APP">%1$s</xliff:g>”正在后台运行,并且消耗了大量电池电量。点按即可查看。"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"“<xliff:g id="APP">%1$s</xliff:g>”已在后台运行较长时间。点按即可查看。"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"查看使用中的应用"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"无法使用此设备的摄像头"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"系统语言"</string>
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 786d5f605ae9..90811367d387 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"允許應用程式要求就該應用程式忽略電池優化。"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"查詢所有套件"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"允許應用程式查看所有已安裝的套件。"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"存取 AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"允許應用程式存取 AdServices Topics API。"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"存取 AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"允許應用程式存取 AdServices Attribution API。"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"存取 AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"允許應用程式存取 AdServices Custom Audiences API。"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"輕觸兩下控制縮放"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"無法新增小工具。"</string>
<string name="ime_action_go" msgid="5536744546326495436">"開始"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"無法使用應用程式"</string>
<string name="app_blocked_message" msgid="542972921087873023">"目前無法使用「<xliff:g id="APP_NAME">%1$s</xliff:g>」。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"無法使用「<xliff:g id="ACTIVITY">%1$s</xliff:g>」"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取此應用程式,請改用 Android TV 裝置存取。"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取此應用程式,請改用平板電腦存取。"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取此應用程式,請改用手機存取。"</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"要允許「<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>」存取所有裝置記錄嗎?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"僅限這次"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"不允許"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"裝置記錄會記下裝置上的活動。應用程式可透過這些記錄找出並修正問題。\n\n部分記錄可能包含敏感資料,因此請只允許信任的應用程式存取所有裝置記錄。\n\n如果不允許這個應用程式存取所有裝置記錄,此應用程式仍能存取自己的記錄,且裝置製造商可能仍可存取裝置上的部分記錄或資料。瞭解詳情"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"不要再顯示"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"「<xliff:g id="APP_0">%1$s</xliff:g>」想顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的快訊"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"編輯"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> 正在背景執行並大量耗電。輕按即可查看。"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> 已長時間在背景執行。輕按即可查看。"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"查看使用中的應用程式"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"無法存取此裝置的相機"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"系統語言"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index afd0f92b3d36..b257d16c47ac 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"允許應用程式要求權限,以便忽略針對該應用程式的電池效能最佳化設定。"</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"查詢所有套件"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"允許應用程式查看所有已安裝的套件。"</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"存取 AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"允許應用程式存取 AdServices Topics API。"</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"存取 AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"允許應用程式存取 AdServices Attribution API。"</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"存取 AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"允許應用程式存取 AdServices Custom Audiences API。"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"點兩下以進行縮放控制"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"無法新增小工具。"</string>
<string name="ime_action_go" msgid="5536744546326495436">"開始"</string>
@@ -1939,6 +1933,8 @@
<string name="app_blocked_title" msgid="7353262160455028160">"應用程式無法使用"</string>
<string name="app_blocked_message" msgid="542972921087873023">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」目前無法使用。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"無法存取「<xliff:g id="ACTIVITY">%1$s</xliff:g>」"</string>
+ <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (4483161748582966785) -->
+ <skip />
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取這個應用程式,請改用 Android TV 裝置。"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取這個應用程式,請改用平板電腦。"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取這個應用程式,請改用手機。"</string>
@@ -2034,7 +2030,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"要允許「<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>」存取所有裝置記錄嗎?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"僅允許這一次"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"不允許"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"系統會透過裝置記錄記下裝置上的活動。應用程式可以根據這些記錄找出問題並進行修正。\n\n某些記錄可能含有機密資訊,因此請勿讓不信任的應用程式存取所有裝置記錄。\n\n即使你不允許這個應用程式存取所有裝置記錄,這個應用程式仍能存取自己的記錄,而且裝置製造商或許仍可存取裝置的某些記錄或資訊。瞭解詳情"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"不要再顯示"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"「<xliff:g id="APP_0">%1$s</xliff:g>」想要顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的區塊"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"編輯"</string>
@@ -2268,7 +2265,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"「<xliff:g id="APP">%1$s</xliff:g>」正在背景運作且耗用大量電力。輕觸即可查看。"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"「<xliff:g id="APP">%1$s</xliff:g>」已長時間在背景運作。輕觸即可查看。"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"查看使用中的應用程式"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"無法存取這部裝置的相機"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"系統語言"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index f094f1226dd4..17bf7a4cc1e5 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1451,12 +1451,6 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Ivumela uhlelo lokusebenza ukuthi licele imvume yokuziba ukulungiselela ibhethri yalolo hlelo lokusebenza."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"buza wonke amaphakheji"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Ivumela i-app ibone wonke amaphakheji afakiwe."</string>
- <string name="permlab_accessAdServicesTopics" msgid="6687112022940098945">"finyelela i-AdServices Topics API"</string>
- <string name="permdesc_accessAdServicesTopics" msgid="6011532458156465929">"Ivumela i-app ukufinyelela i-AdServices Topics API."</string>
- <string name="permlab_accessAdServicesAttribution" msgid="3268942271128309354">"finyelela ama-AdServices Attribution API"</string>
- <string name="permdesc_accessAdServicesAttribution" msgid="577482544832578288">"Ivumela i-app ukufinyelela kuma-AdServices Attribution API."</string>
- <string name="permlab_accessAdServicesCustomAudiences" msgid="7249286630514600684">"finyelela i-AdServices Custom Audiences API"</string>
- <string name="permdesc_accessAdServicesCustomAudiences" msgid="645526926477180315">"Ivumela i-app ukufinyelela i-AdServices Custom Audiences API."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Thepha kabili ukuthola ukulawula ukusondeza"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Yehlulekile ukwengeza i-widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Iya"</string>
@@ -1939,6 +1933,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Uhlelo lokusebenza alutholakali"</string>
<string name="app_blocked_message" msgid="542972921087873023">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayitholakali khona manje."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"okungatholakali <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Kudingeka imvume"</string>
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Lokhu akukwazi ukufinyelelwa ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho ngalesi sikhathi. Zama kudivayisi yakho ye-Android TV kunalokho."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Lokhu akukwazi ukufinyelelwa ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho ngalesi sikhathi. Zama kuthebhulethi yakho kunalokho."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Lokhu akukwazi ukufinyelelwa ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho ngalesi sikhathi. Zama efonini yakho kunalokho."</string>
@@ -2034,7 +2029,8 @@
<string name="log_access_confirmation_title" msgid="2343578467290592708">"Vumela i-<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ukuba ifinyelele wonke amalogu edivayisi?"</string>
<string name="log_access_confirmation_allow" msgid="143157286283302512">"Kulokhu kuphela"</string>
<string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ungavumeli"</string>
- <string name="log_access_confirmation_body" msgid="4483075525611652922">"Amalogu edivayisi arekhoda okwenzekayo kudivayisi yakho. Ama-app angasebenzisa lawa malogu ukuze athole futhi alungise izinkinga.\n\nAmanye amalogu angase aqukathe ulwazi olubucayi, ngakho vumela ama-app owathembayo kuphela ukuthi afinyelele wonke amalogu edivayisi. \n\nUma ungayivumeli le-app ukuthi ifinyelele wonke amalogu edivayisi, isengakwazi ukufinyelela amalogu ayo futhi umkhiqizi wedivayisi yakho usengakwazi ukufinyelela amanye amalogu noma ulwazi kudivayisi yakho. Funda kabanzi"</string>
+ <!-- no translation found for log_access_confirmation_body (6581985716241928135) -->
+ <skip />
<string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ungabonisi futhi"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"I-<xliff:g id="APP_0">%1$s</xliff:g> ifuna ukubonisa izingcezu ze-<xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Hlela"</string>
@@ -2268,7 +2264,9 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"I-<xliff:g id="APP">%1$s</xliff:g> isebenza ngemuva futhi idla ibhethri. Thepha ukuze ubuyekeze."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"I-<xliff:g id="APP">%1$s</xliff:g> isebenza ngemuva isikhathi eside. Thepha ukuze ubuyekeze."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Hlola ama-app asebenzayo"</string>
- <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Ayikwazi ukufinyelela ikhamera kule divayisi"</string>
- <!-- no translation found for system_locale_title (3978041860457277638) -->
+ <!-- no translation found for vdm_camera_access_denied (6102378580971542473) -->
+ <skip />
+ <!-- no translation found for vdm_camera_access_denied (6895968310395249076) -->
<skip />
+ <string name="system_locale_title" msgid="3978041860457277638">"Ulimi lwesistimu"</string>
</resources>
diff --git a/core/res/res/values/colors_car.xml b/core/res/res/values/colors_car.xml
index 82caa265e7ec..d7d222c07b17 100644
--- a/core/res/res/values/colors_car.xml
+++ b/core/res/res/values/colors_car.xml
@@ -133,8 +133,8 @@
<!-- The color of the seekbar track background in SeekbarListItem. This color is assumed to be
on a light-colored background. -->
<color name="car_seekbar_track_background">@color/car_seekbar_track_background_dark</color>
- <!-- background is car_grey_868 with .9 alpha -->
- <color name="car_toast_background">#E6282a2d</color>
+ <!-- background is car_grey_868 with -->
+ <color name="car_toast_background">@color/car_grey_868</color>
<!-- Misc colors -->
<color name="car_highlight_light">#ff66b5ff</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 94eb45cab8d6..29ca3bffb6aa 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2403,6 +2403,9 @@
<!-- Limit of how long the device can remain unlocked due to attention checking. -->
<integer name="config_attentionMaximumExtension">900000</integer> <!-- 15 minutes. -->
+ <!-- The prefix of dream component names that are loggable. If empty, logs "other" for all. -->
+ <string name ="config_loggable_dream_prefix" translatable="false"></string>
+
<!-- ComponentName of a dream to show whenever the system would otherwise have
gone to sleep. When the PowerManager is asked to go to sleep, it will instead
try to start this dream if possible. The dream should typically call startDozing()
@@ -2693,23 +2696,27 @@
rat-name:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max
If no value is found for the rat-name in use, the system default will be applied.
- This is deprecated. Please use config_tcp_buffers.
+ This is deprecated. Please use config_mobile_tcp_buffers for rat-based TCP buffers sizes or
+ config_tcp_buffers for rat-independent TCP buffer sizes.
-->
<string-array name="config_mobile_tcp_buffers">
</string-array>
+ <!-- Configure tcp buffer sizes per network type in the form:
+ network-type:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max
+
+ The network-type must be a valid DataConfigNetworkType value. If no value is found for the
+ network-type in use, config_tcp_buffers will be used instead.
+ -->
+ <string-array name="config_network_type_tcp_buffers">
+ </string-array>
+
<!-- Configure tcp buffer sizes in the form:
rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max
If this is configured as an empty string, the system default will be applied.
For now this config is used by mobile data only. In the future it should be
used by Wi-Fi as well.
-
- Note that starting from Android 13, the TCP buffer size is fixed after boot up, and should
- never be changed based on carriers or the network types. The value should be configured
- appropriately based on the device's memory and performance. It is recommended to use lower
- values if the device has low memory or doesn't support high-speed network such like LTE,
- NR, or Wifi.
-->
<string name="config_tcp_buffers" translatable="false"></string>
@@ -2725,6 +2732,11 @@
<!-- Whether force to enable telephony new data stack or not -->
<bool name="config_force_enable_telephony_new_data_stack">true</bool>
+ <!-- Whether to adopt the predefined handover policies for IWLAN.
+ {@see CarrierConfigManager#KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY}
+ -->
+ <bool name="config_enable_iwlan_handover_policy">true</bool>
+
<!-- Whether WiFi display is supported by this device.
There are many prerequisites for this feature to work correctly.
Here are a few of them:
@@ -4101,12 +4113,6 @@
<!-- Intent extra key for the event code int array while requesting ambient context consent. -->
<string translatable="false" name="config_ambientContextEventArrayExtraKey"></string>
- <!-- The component name for the system-wide captions service.
- This service must be trusted, as it controls part of the UI of the volume bar.
- Example: "com.android.captions/.SystemCaptionsService"
- -->
- <string name="config_defaultSystemCaptionsService" translatable="false"></string>
-
<!-- The component name for the system-wide captions manager service.
This service must be trusted, as the system binds to it and keeps it running.
Example: "com.android.captions/.SystemCaptionsManagerService"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 34c706d3c2a9..1b947e961f36 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -6265,14 +6265,16 @@ ul.</string>
<!-- Title for the notification channel notifying user of abusive background apps. [CHAR LIMIT=NONE] -->
<string name="notification_channel_abusive_bg_apps">Background Activity</string>
<!-- Title of notification indicating abusive background apps. [CHAR LIMIT=NONE] -->
- <string name="notification_title_abusive_bg_apps">Background Activity</string>
+ <string name="notification_title_abusive_bg_apps">An app is using battery</string>
+ <!-- Title of notification indicating long running foreground services. [CHAR LIMIT=NONE] -->
+ <string name="notification_title_long_running_fgs">An app is still active</string>
<!-- Content of notification indicating abusive background apps. [CHAR LIMIT=NONE] -->
<string name="notification_content_abusive_bg_apps">
- <xliff:g id="app" example="Gmail">%1$s</xliff:g> is running in the background and draining battery. Tap to review.
+ <xliff:g id="app" example="Gmail">%1$s</xliff:g> is using battery in the background. Tap to review.
</string>
<!-- Content of notification indicating long running foreground service. [CHAR LIMIT=NONE] -->
<string name="notification_content_long_running_fgs">
- <xliff:g id="app" example="Gmail">%1$s</xliff:g> is running in the background for a long time. Tap to review.
+ <xliff:g id="app" example="Gmail">%1$s</xliff:g> might affect battery life. Tap to review active apps.
</string>
<!-- Action label of notification for user to check background apps. [CHAR LIMIT=NONE] -->
<string name="notification_action_check_bg_apps">Check active apps</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index bb9142a56db3..8fa5dd2c756b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -472,8 +472,10 @@
<java-symbol type="integer" name="config_safe_media_volume_usb_mB" />
<java-symbol type="integer" name="config_mobile_mtu" />
<java-symbol type="array" name="config_mobile_tcp_buffers" />
+ <java-symbol type="array" name="config_network_type_tcp_buffers" />
<java-symbol type="string" name="config_tcp_buffers" />
<java-symbol type="bool" name="config_force_enable_telephony_new_data_stack" />
+ <java-symbol type="bool" name="config_enable_iwlan_handover_policy" />
<java-symbol type="integer" name="config_volte_replacement_rat"/>
<java-symbol type="integer" name="config_valid_wappush_index" />
<java-symbol type="integer" name="config_overrideHasPermanentMenuKey" />
@@ -1714,10 +1716,6 @@
<java-symbol type="anim" name="activity_open_exit" />
<java-symbol type="anim" name="activity_close_enter" />
<java-symbol type="anim" name="activity_close_exit" />
- <java-symbol type="anim" name="activity_open_enter_legacy" />
- <java-symbol type="anim" name="activity_open_exit_legacy" />
- <java-symbol type="anim" name="activity_close_enter_legacy" />
- <java-symbol type="anim" name="activity_close_exit_legacy" />
<java-symbol type="anim" name="task_fragment_close_enter" />
<java-symbol type="anim" name="task_fragment_close_exit" />
<java-symbol type="anim" name="task_fragment_open_enter" />
@@ -2237,6 +2235,7 @@
<java-symbol type="array" name="config_supportedDreamComplications" />
<java-symbol type="array" name="config_dreamComplicationsEnabledByDefault" />
<java-symbol type="array" name="config_disabledDreamComponents" />
+ <java-symbol type="string" name="config_loggable_dream_prefix" />
<java-symbol type="string" name="config_dozeComponent" />
<java-symbol type="string" name="enable_explore_by_touch_warning_title" />
<java-symbol type="string" name="enable_explore_by_touch_warning_message" />
@@ -3707,7 +3706,6 @@
<java-symbol type="string" name="config_defaultMusicRecognitionService" />
<java-symbol type="string" name="config_defaultAttentionService" />
<java-symbol type="string" name="config_defaultRotationResolverService" />
- <java-symbol type="string" name="config_defaultSystemCaptionsService" />
<java-symbol type="string" name="config_defaultSystemCaptionsManagerService" />
<java-symbol type="string" name="config_defaultAmbientContextDetectionService" />
<java-symbol type="string" name="config_defaultAmbientContextConsentComponent" />
@@ -4742,6 +4740,7 @@
<java-symbol type="string" name="notification_channel_abusive_bg_apps"/>
<java-symbol type="string" name="notification_title_abusive_bg_apps"/>
+ <java-symbol type="string" name="notification_title_long_running_fgs"/>
<java-symbol type="string" name="notification_content_abusive_bg_apps"/>
<java-symbol type="string" name="notification_content_long_running_fgs"/>
<java-symbol type="string" name="notification_action_check_bg_apps"/>
diff --git a/core/tests/coretests/src/android/companion/virtual/audio/VirtualAudioSessionTest.java b/core/tests/coretests/src/android/companion/virtual/audio/VirtualAudioSessionTest.java
index 0e09d563c884..e025fae4b909 100644
--- a/core/tests/coretests/src/android/companion/virtual/audio/VirtualAudioSessionTest.java
+++ b/core/tests/coretests/src/android/companion/virtual/audio/VirtualAudioSessionTest.java
@@ -167,7 +167,7 @@ public class VirtualAudioSessionTest {
public void onPlaybackConfigChanged_sendsCallback() {
List<AudioPlaybackConfiguration> configs = new ArrayList<>();
- mVirtualAudioSession.onPlaybackConfigChanged(configs);
+ mVirtualAudioSession.getAudioConfigChangedListener().onPlaybackConfigChanged(configs);
verify(mCallback, timeout(2000)).onPlaybackConfigChanged(configs);
}
@@ -176,7 +176,7 @@ public class VirtualAudioSessionTest {
public void onRecordingConfigChanged_sendCallback() {
List<AudioRecordingConfiguration> configs = new ArrayList<>();
- mVirtualAudioSession.onRecordingConfigChanged(configs);
+ mVirtualAudioSession.getAudioConfigChangedListener().onRecordingConfigChanged(configs);
verify(mCallback, timeout(2000)).onRecordingConfigChanged(configs);
}
diff --git a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
index 01cf311f63b1..114317abc07c 100644
--- a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
+++ b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
@@ -16,6 +16,10 @@
package android.hardware.display;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+import android.annotation.ColorInt;
+import android.app.Dialog;
import android.app.Presentation;
import android.content.Context;
import android.graphics.Color;
@@ -33,8 +37,11 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
+import android.view.View;
import android.view.ViewGroup.LayoutParams;
+import android.view.Window;
import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams.Flags;
import android.widget.ImageView;
import androidx.test.filters.LargeTest;
@@ -110,7 +117,7 @@ public class VirtualDisplayTest extends AndroidTestCase {
* Ensures that an application can create a private virtual display and show
* its own windows on it.
*/
- public void testPrivateVirtualDisplay() throws Exception {
+ public void testPrivateVirtualDisplay() {
VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
WIDTH, HEIGHT, DENSITY, mSurface, 0);
assertNotNull("virtual display must not be null", virtualDisplay);
@@ -120,9 +127,7 @@ public class VirtualDisplayTest extends AndroidTestCase {
assertDisplayRegistered(display, Display.FLAG_PRIVATE);
// Show a private presentation on the display.
- assertDisplayCanShowPresentation("private presentation window",
- display, BLUEISH,
- WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION, 0);
+ assertDisplayCanShowPresentation("private presentation window", display, BLUEISH, 0);
} finally {
virtualDisplay.release();
}
@@ -133,10 +138,9 @@ public class VirtualDisplayTest extends AndroidTestCase {
* Ensures that an application can create a private presentation virtual display and show
* its own windows on it.
*/
- public void testPrivatePresentationVirtualDisplay() throws Exception {
+ public void testPrivatePresentationVirtualDisplay() {
VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
- WIDTH, HEIGHT, DENSITY, mSurface,
- DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION);
+ WIDTH, HEIGHT, DENSITY, mSurface, DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION);
assertNotNull("virtual display must not be null", virtualDisplay);
Display display = virtualDisplay.getDisplay();
@@ -144,9 +148,7 @@ public class VirtualDisplayTest extends AndroidTestCase {
assertDisplayRegistered(display, Display.FLAG_PRIVATE | Display.FLAG_PRESENTATION);
// Show a private presentation on the display.
- assertDisplayCanShowPresentation("private presentation window",
- display, BLUEISH,
- WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION, 0);
+ assertDisplayCanShowPresentation("private presentation window", display, BLUEISH, 0);
} finally {
virtualDisplay.release();
}
@@ -161,7 +163,7 @@ public class VirtualDisplayTest extends AndroidTestCase {
* type to create the window. Another choice might be SYSTEM_ALERT_WINDOW but
* that requires a permission.
*/
- public void testPublicPresentationVirtualDisplay() throws Exception {
+ public void testPublicPresentationVirtualDisplay() {
VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
WIDTH, HEIGHT, DENSITY, mSurface,
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
@@ -177,29 +179,22 @@ public class VirtualDisplayTest extends AndroidTestCase {
// virtual display automatically.
Display defaultDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
assertDisplayCanShowPresentation("mirrored window",
- defaultDisplay, GREENISH,
- WindowManager.LayoutParams.TYPE_TOAST, 0);
+ defaultDisplay, GREENISH, 0);
// Mirroring case with secure window (but display is not secure).
// Show a window on the default display. It should be replaced with black on
// the virtual display.
assertDisplayCanShowPresentation("mirrored secure window on non-secure display",
- defaultDisplay, Color.BLACK,
- WindowManager.LayoutParams.TYPE_TOAST,
- WindowManager.LayoutParams.FLAG_SECURE);
+ defaultDisplay, Color.BLACK, WindowManager.LayoutParams.FLAG_SECURE);
// Presentation case.
// Show a normal presentation on the display.
- assertDisplayCanShowPresentation("presentation window",
- display, BLUEISH,
- WindowManager.LayoutParams.TYPE_TOAST, 0);
+ assertDisplayCanShowPresentation("presentation window", display, BLUEISH, 0);
// Presentation case with secure window (but display is not secure).
// Show a normal presentation on the display. It should be replaced with black.
assertDisplayCanShowPresentation("secure presentation window on non-secure display",
- display, Color.BLACK,
- WindowManager.LayoutParams.TYPE_TOAST,
- WindowManager.LayoutParams.FLAG_SECURE);
+ display, Color.BLACK, WindowManager.LayoutParams.FLAG_SECURE);
} finally {
virtualDisplay.release();
}
@@ -214,7 +209,7 @@ public class VirtualDisplayTest extends AndroidTestCase {
* type to create the window. Another choice might be SYSTEM_ALERT_WINDOW but
* that requires a permission.
*/
- public void testSecurePublicPresentationVirtualDisplay() throws Exception {
+ public void testSecurePublicPresentationVirtualDisplay() {
VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
WIDTH, HEIGHT, DENSITY, mSurface,
DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE
@@ -231,16 +226,12 @@ public class VirtualDisplayTest extends AndroidTestCase {
// virtual display automatically.
Display defaultDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
assertDisplayCanShowPresentation("mirrored secure window on secure display",
- defaultDisplay, GREENISH,
- WindowManager.LayoutParams.TYPE_TOAST,
- WindowManager.LayoutParams.FLAG_SECURE);
+ defaultDisplay, GREENISH, WindowManager.LayoutParams.FLAG_SECURE);
// Presentation case with secure window (and display is secure).
// Show a normal presentation on the display.
assertDisplayCanShowPresentation("secure presentation window on secure display",
- display, BLUEISH,
- WindowManager.LayoutParams.TYPE_TOAST,
- WindowManager.LayoutParams.FLAG_SECURE);
+ display, BLUEISH, WindowManager.LayoutParams.FLAG_SECURE);
} finally {
virtualDisplay.release();
}
@@ -251,7 +242,7 @@ public class VirtualDisplayTest extends AndroidTestCase {
* Ensures that an application can create a trusted virtual display with the permission
* {@code ADD_TRUSTED_DISPLAY}.
*/
- public void testTrustedVirtualDisplay() throws Exception {
+ public void testTrustedVirtualDisplay() {
VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
WIDTH, HEIGHT, DENSITY, mSurface,
DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED);
@@ -299,35 +290,43 @@ public class VirtualDisplayTest extends AndroidTestCase {
assertFalse("display must no longer be valid", display.isValid());
}
+ /**
+ * Verifies that virtual display shows the expected {@code color}.
+ * <p>
+ * If {@code display} is the {@link Display#DEFAULT_DISPLAY default display}, show a fullscreen
+ * overlay {@link Dialog} on the default display and verify if the dialog is mirrored to the
+ * virtual display.
+ * </p><p>
+ * If {@code display} is a {@link VirtualDisplay}, show a {@link Presentation} on that virtual
+ * display and verify the content.
+ * </p>
+ */
private void assertDisplayCanShowPresentation(String message, final Display display,
- final int color, final int windowType, final int windowFlags) {
+ @ColorInt final int color, @Flags final int windowFlags) {
// At this point, we should not have seen any blue.
assertTrue(message + ": display should not show content before window is shown",
mImageListener.getColor() != color);
- final TestPresentation[] presentation = new TestPresentation[1];
+ final Dialog[] dialogs = new Dialog[1];
try {
// Show the presentation.
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- presentation[0] = new TestPresentation(getContext(), display,
- color, windowType, windowFlags);
- presentation[0].show();
+ runOnUiThread(() -> {
+ if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
+ final Context windowContext = getContext().createWindowContext(display,
+ TYPE_APPLICATION_OVERLAY, null /* options */);
+ dialogs[0] = new TestDialog(windowContext, color, windowFlags);
+ } else {
+ dialogs[0] = new TestPresentation(getContext(), display, color, windowFlags);
}
+ dialogs[0].show();
});
- // Wait for the blue to be seen.
+ // Wait for the color to be seen.
assertTrue(message + ": display should show content after window is shown",
mImageListener.waitForColor(color, TIMEOUT));
} finally {
- if (presentation[0] != null) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- presentation[0].dismiss();
- }
- });
+ if (dialogs[0] != null) {
+ runOnUiThread(() -> dialogs[0].dismiss());
}
}
}
@@ -360,13 +359,15 @@ public class VirtualDisplayTest extends AndroidTestCase {
return null;
}
- private final class TestPresentation extends Presentation {
+ private static final class TestPresentation extends Presentation {
+ @ColorInt
private final int mColor;
+ @Flags
private final int mWindowFlags;
- public TestPresentation(Context context, Display display,
- int color, int windowType, int windowFlags) {
- super(context, display, 0 /* theme */, windowType);
+ TestPresentation(Context context, Display display, @ColorInt int color,
+ @Flags int windowFlags) {
+ super(context, display);
mColor = color;
mWindowFlags = windowFlags;
}
@@ -378,15 +379,44 @@ public class VirtualDisplayTest extends AndroidTestCase {
setTitle(TAG);
getWindow().addFlags(mWindowFlags);
- // Create a solid color image to use as the content of the presentation.
- ImageView view = new ImageView(getContext());
- view.setImageDrawable(new ColorDrawable(mColor));
- view.setLayoutParams(new LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- setContentView(view);
+ setContentView(createImageView(getContext(), mColor));
}
}
+ private static final class TestDialog extends Dialog {
+ @ColorInt
+ private final int mColor;
+ @Flags
+ private final int mWindowFlags;
+
+ TestDialog(Context context, @ColorInt int color, @Flags int windowFlags) {
+ super(context, android.R.style.Theme_Material_NoActionBar_Fullscreen);
+ mColor = color;
+ mWindowFlags = windowFlags;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setTitle(TAG);
+ final Window window = getWindow();
+ window.setType(TYPE_APPLICATION_OVERLAY);
+ window.addFlags(mWindowFlags);
+
+ setContentView(createImageView(getContext(), mColor));
+ }
+ }
+
+ private static View createImageView(Context context, @ColorInt int color) {
+ // Create a solid color image to use as the content of the presentation.
+ ImageView view = new ImageView(context);
+ view.setImageDrawable(new ColorDrawable(color));
+ view.setLayoutParams(new LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+ return view;
+ }
+
/**
* Watches for an image with a large amount of some particular solid color to be shown.
*/
diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
index 4dd4d1c7bd12..3766cd4ebab1 100644
--- a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
+++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
@@ -486,6 +486,20 @@ public class IPrintManagerParametersTest extends BasePrintTest {
}
/**
+ * test IPrintManager.isPrintServiceEnabled
+ */
+ @MediumTest
+ @Test
+ @NoActivity
+ public void testIsPrintServiceEnabled() throws Throwable {
+ assertException(() -> mIPrintManager.isPrintServiceEnabled(new ComponentName("bad", "name"),
+ mUserId), SecurityException.class);
+
+ assertException(() -> mIPrintManager.isPrintServiceEnabled(null, mUserId),
+ SecurityException.class);
+ }
+
+ /**
* test IPrintManager.addPrintServiceRecommendationsChangeListener
*/
@MediumTest
diff --git a/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
new file mode 100644
index 000000000000..9d7d71d8d539
--- /dev/null
+++ b/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.Matrix;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CursorAnchorInfoTest {
+ @Test
+ public void testCreateForAdditionalParentMatrix() {
+ final Matrix originalMatrix = new Matrix();
+ originalMatrix.setTranslate(10.0f, 20.0f);
+ final CursorAnchorInfo.Builder builder = new CursorAnchorInfo.Builder();
+ builder.setMatrix(originalMatrix);
+
+ final CursorAnchorInfo originalInstance = builder.build();
+
+ assertEquals(originalMatrix, originalInstance.getMatrix());
+
+ final Matrix additionalParentMatrix = new Matrix();
+ additionalParentMatrix.setTranslate(1.0f, 2.0f);
+
+ final Matrix newMatrix = new Matrix(originalMatrix);
+ newMatrix.postConcat(additionalParentMatrix);
+
+ builder.reset();
+ builder.setMatrix(newMatrix);
+ // An instance created by the standard Builder class.
+ final CursorAnchorInfo newInstanceByBuilder = builder.build();
+
+ // An instance created by an @hide method.
+ final CursorAnchorInfo newInstanceByMethod =
+ CursorAnchorInfo.createForAdditionalParentMatrix(
+ originalInstance, additionalParentMatrix);
+
+ assertEquals(newMatrix, newInstanceByBuilder.getMatrix());
+ assertEquals(newMatrix, newInstanceByMethod.getMatrix());
+ assertEquals(newInstanceByBuilder.hashCode(), newInstanceByMethod.hashCode());
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
index 7cd8197ce1e4..0f48465e0bdd 100644
--- a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
@@ -23,11 +23,14 @@ import static android.view.SurfaceControl.JankData.JANK_SURFACEFLINGER_DEADLINE_
import static com.android.internal.jank.FrameTracker.SurfaceControlWrapper;
import static com.android.internal.jank.FrameTracker.ViewRootWrapper;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_TO_STATSD_INTERACTION_TYPE;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_WALLPAPER_TRANSITION;
+import static com.android.internal.util.FrameworkStatsLog.UI_INTERACTION_FRAME_INFO_REPORTED;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -50,6 +53,7 @@ import androidx.test.rule.ActivityTestRule;
import com.android.internal.jank.FrameTracker.ChoreographerWrapper;
import com.android.internal.jank.FrameTracker.FrameMetricsWrapper;
+import com.android.internal.jank.FrameTracker.StatsLogWrapper;
import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.internal.jank.InteractionJankMonitor.Session;
@@ -76,6 +80,7 @@ public class FrameTrackerTest {
private SurfaceControlWrapper mSurfaceControlWrapper;
private ViewRootWrapper mViewRootWrapper;
private ChoreographerWrapper mChoreographer;
+ private StatsLogWrapper mStatsLog;
private ArgumentCaptor<OnJankDataListener> mListenerCapture;
private SurfaceControl mSurfaceControl;
@@ -103,6 +108,7 @@ public class FrameTrackerTest {
mListenerCapture.capture());
mChoreographer = mock(ChoreographerWrapper.class);
+ mStatsLog = mock(StatsLogWrapper.class);
}
private FrameTracker spyFrameTracker(int cuj, String postfix, boolean surfaceOnly) {
@@ -111,9 +117,10 @@ public class FrameTrackerTest {
Configuration config = mock(Configuration.class);
when(config.isSurfaceOnly()).thenReturn(surfaceOnly);
when(config.getSurfaceControl()).thenReturn(mSurfaceControl);
+ when(config.shouldDeferMonitor()).thenReturn(true);
FrameTracker frameTracker = Mockito.spy(
new FrameTracker(session, handler, mRenderer, mViewRootWrapper,
- mSurfaceControlWrapper, mChoreographer, mWrapper,
+ mSurfaceControlWrapper, mChoreographer, mWrapper, mStatsLog,
/* traceThresholdMissedFrames= */ 1,
/* traceThresholdFrameTimeMillis= */ -1,
/* FrameTrackerListener= */ null, config));
@@ -139,7 +146,7 @@ public class FrameTrackerTest {
sendFirstWindowFrame(tracker, 100, JANK_APP_DEADLINE_MISSED, 100L);
// send another frame with a short duration - should not be considered janky
- sendFirstWindowFrame(tracker, 5, JANK_NONE, 101L);
+ sendFrame(tracker, 5, JANK_NONE, 101L);
// end the trace session, the last janky frame is after the end() so is discarded.
when(mChoreographer.getVsyncId()).thenReturn(102L);
@@ -149,6 +156,13 @@ public class FrameTrackerTest {
verify(tracker).removeObservers();
verify(tracker, never()).triggerPerfetto();
+ verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+ eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
+ eq(2L) /* totalFrames */,
+ eq(0L) /* missedFrames */,
+ eq(5000000L) /* maxFrameTimeNanos */,
+ eq(0L) /* missedSfFramesCount */,
+ eq(0L) /* missedAppFramesCount */);
}
@Test
@@ -175,6 +189,14 @@ public class FrameTrackerTest {
// We detected a janky frame - trigger Perfetto
verify(tracker).triggerPerfetto();
+
+ verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+ eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
+ eq(2L) /* totalFrames */,
+ eq(1L) /* missedFrames */,
+ eq(40000000L) /* maxFrameTimeNanos */,
+ eq(1L) /* missedSfFramesCount */,
+ eq(0L) /* missedAppFramesCount */);
}
@Test
@@ -201,6 +223,14 @@ public class FrameTrackerTest {
// We detected a janky frame - trigger Perfetto
verify(tracker, never()).triggerPerfetto();
+
+ verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+ eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
+ eq(2L) /* totalFrames */,
+ eq(0L) /* missedFrames */,
+ eq(4000000L) /* maxFrameTimeNanos */,
+ eq(0L) /* missedSfFramesCount */,
+ eq(0L) /* missedAppFramesCount */);
}
@Test
@@ -227,6 +257,14 @@ public class FrameTrackerTest {
// We detected a janky frame - trigger Perfetto
verify(tracker).triggerPerfetto();
+
+ verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+ eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
+ eq(2L) /* totalFrames */,
+ eq(1L) /* missedFrames */,
+ eq(40000000L) /* maxFrameTimeNanos */,
+ eq(0L) /* missedSfFramesCount */,
+ eq(1L) /* missedAppFramesCount */);
}
@Test
@@ -256,6 +294,53 @@ public class FrameTrackerTest {
// We detected a janky frame - trigger Perfetto
verify(tracker).triggerPerfetto();
+
+ verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+ eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
+ eq(2L) /* totalFrames */,
+ eq(1L) /* missedFrames */,
+ eq(50000000L) /* maxFrameTimeNanos */,
+ eq(0L) /* missedSfFramesCount */,
+ eq(1L) /* missedAppFramesCount */);
+ }
+
+ /**
+ * b/223787365
+ */
+ @Test
+ public void testNoOvercountingAfterEnd() {
+ FrameTracker tracker = spyFrameTracker(
+ CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
+ when(mChoreographer.getVsyncId()).thenReturn(100L);
+ tracker.begin();
+ verify(mRenderer, only()).addObserver(any());
+
+ // send first frame - not janky
+ sendFrame(tracker, 4, JANK_NONE, 100L);
+
+ // send another frame - not janky
+ sendFrame(tracker, 4, JANK_NONE, 101L);
+
+ // end the trace session, simulate one more valid callback came after the end call.
+ when(mChoreographer.getVsyncId()).thenReturn(102L);
+ tracker.end(FrameTracker.REASON_END_NORMAL);
+
+ // Send incomplete callback for 102L
+ sendSfFrame(102L, JANK_NONE);
+
+ // Send janky but complete callbck fo 103L
+ sendFrame(tracker, 50, JANK_APP_DEADLINE_MISSED, 103L);
+
+ verify(tracker).removeObservers();
+ verify(tracker, never()).triggerPerfetto();
+ verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+ eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
+ eq(2L) /* totalFrames */,
+ eq(0L) /* missedFrames */,
+ eq(4000000L) /* maxFrameTimeNanos */,
+ eq(0L) /* missedSfFramesCount */,
+ eq(0L) /* missedAppFramesCount */);
}
@Test
@@ -370,6 +455,14 @@ public class FrameTrackerTest {
verify(mSurfaceControlWrapper).removeJankStatsListener(any());
verify(tracker).triggerPerfetto();
+
+ verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+ eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION]),
+ eq(2L) /* totalFrames */,
+ eq(1L) /* missedFrames */,
+ eq(0L) /* maxFrameTimeNanos */,
+ eq(0L) /* missedSfFramesCount */,
+ eq(1L) /* missedAppFramesCount */);
}
@Test
@@ -396,6 +489,14 @@ public class FrameTrackerTest {
verify(mSurfaceControlWrapper).removeJankStatsListener(any());
verify(tracker, never()).triggerPerfetto();
+
+ verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+ eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION]),
+ eq(2L) /* totalFrames */,
+ eq(0L) /* missedFrames */,
+ eq(0L) /* maxFrameTimeNanos */,
+ eq(0L) /* missedSfFramesCount */,
+ eq(0L) /* missedAppFramesCount */);
}
@Test
@@ -422,6 +523,14 @@ public class FrameTrackerTest {
verify(mSurfaceControlWrapper).removeJankStatsListener(any());
verify(tracker, never()).triggerPerfetto();
+
+ verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+ eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION]),
+ eq(2L) /* totalFrames */,
+ eq(0L) /* missedFrames */,
+ eq(0L) /* maxFrameTimeNanos */,
+ eq(0L) /* missedSfFramesCount */,
+ eq(0L) /* missedAppFramesCount */);
}
private void sendFirstWindowFrame(FrameTracker tracker, long durationMillis,
@@ -445,13 +554,22 @@ public class FrameTrackerTest {
private void sendFrame(FrameTracker tracker, long durationMillis,
@JankType int jankType, long vsyncId, boolean firstWindowFrame) {
if (!tracker.mSurfaceOnly) {
- when(mWrapper.getTiming()).thenReturn(new long[]{0, vsyncId});
- doReturn(firstWindowFrame ? 1L : 0L).when(mWrapper)
- .getMetric(FrameMetrics.FIRST_DRAW_FRAME);
- doReturn(TimeUnit.MILLISECONDS.toNanos(durationMillis))
- .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION);
- tracker.onFrameMetricsAvailable(0);
+ sendHwuiFrame(tracker, durationMillis, vsyncId, firstWindowFrame);
}
+ sendSfFrame(vsyncId, jankType);
+ }
+
+ private void sendHwuiFrame(FrameTracker tracker, long durationMillis, long vsyncId,
+ boolean firstWindowFrame) {
+ when(mWrapper.getTiming()).thenReturn(new long[]{0, vsyncId});
+ doReturn(firstWindowFrame ? 1L : 0L).when(mWrapper)
+ .getMetric(FrameMetrics.FIRST_DRAW_FRAME);
+ doReturn(TimeUnit.MILLISECONDS.toNanos(durationMillis))
+ .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION);
+ tracker.onFrameMetricsAvailable(0);
+ }
+
+ private void sendSfFrame(long vsyncId, @JankType int jankType) {
mListenerCapture.getValue().onJankDataAvailable(new JankData[] {
new JankData(vsyncId, jankType)
});
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
index a4091294aa70..5a6fd5317bbc 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -46,6 +46,7 @@ import androidx.test.rule.ActivityTestRule;
import com.android.internal.jank.FrameTracker.ChoreographerWrapper;
import com.android.internal.jank.FrameTracker.FrameMetricsWrapper;
+import com.android.internal.jank.FrameTracker.StatsLogWrapper;
import com.android.internal.jank.FrameTracker.SurfaceControlWrapper;
import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper;
import com.android.internal.jank.FrameTracker.ViewRootWrapper;
@@ -202,7 +203,8 @@ public class InteractionJankMonitorTest {
FrameTracker tracker = spy(new FrameTracker(session, mWorker.getThreadHandler(),
threadedRenderer, viewRoot, surfaceControl, choreographer,
- new FrameMetricsWrapper(), /* traceThresholdMissedFrames= */ 1,
+ new FrameMetricsWrapper(), new StatsLogWrapper(),
+ /* traceThresholdMissedFrames= */ 1,
/* traceThresholdFrameTimeMillis= */ -1, listener, configuration));
doNothing().when(tracker).postTraceStartMarker();
diff --git a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
index 95225b2e4f39..00ac1985f897 100644
--- a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
@@ -269,8 +269,9 @@ public class MobileRadioPowerCalculatorTest {
.isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
+ // 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
- .isWithin(PRECISION).of(4.31711);
+ .isWithin(PRECISION).of(2.77778);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
diff --git a/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java b/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java
index d8b37803f568..033c3cae5beb 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java
@@ -145,6 +145,56 @@ public class LocalImageResolverTest {
}
@Test
+ public void resolveImage_largeResourceIcon_negativeWidth_dontResize() {
+ Icon icon = Icon.createWithResource(mContext, R.drawable.big_a);
+ Drawable d = LocalImageResolver.resolveImage(icon, mContext, LocalImageResolver.NO_MAX_SIZE,
+ 50);
+
+ assertThat(d).isInstanceOf(BitmapDrawable.class);
+ BitmapDrawable bd = (BitmapDrawable) d;
+ assertThat(bd.getBitmap().getWidth()).isGreaterThan(101);
+ assertThat(bd.getBitmap().getHeight()).isGreaterThan(51);
+ }
+
+ @Test
+ public void resolveImage_largeResourceIcon_negativeHeight_dontResize() {
+ Icon icon = Icon.createWithResource(mContext, R.drawable.big_a);
+ Drawable d = LocalImageResolver.resolveImage(icon, mContext, 100,
+ LocalImageResolver.NO_MAX_SIZE);
+
+ assertThat(d).isInstanceOf(BitmapDrawable.class);
+ BitmapDrawable bd = (BitmapDrawable) d;
+ assertThat(bd.getBitmap().getWidth()).isGreaterThan(101);
+ assertThat(bd.getBitmap().getHeight()).isGreaterThan(51);
+ }
+
+ @Test
+ public void resolveImage_largeBitmapIcon_passedNegativeWidth_dontResize() {
+ Icon icon = Icon.createWithBitmap(
+ BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
+ Drawable d = LocalImageResolver.resolveImage(icon, mContext, LocalImageResolver.NO_MAX_SIZE,
+ 50);
+
+ assertThat(d).isInstanceOf(BitmapDrawable.class);
+ BitmapDrawable bd = (BitmapDrawable) d;
+ assertThat(bd.getBitmap().getWidth()).isGreaterThan(101);
+ assertThat(bd.getBitmap().getHeight()).isGreaterThan(51);
+ }
+
+ @Test
+ public void resolveImage_largeBitmapIcon_passedNegativeHeight_dontResize() {
+ Icon icon = Icon.createWithBitmap(
+ BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
+ Drawable d = LocalImageResolver.resolveImage(icon, mContext, LocalImageResolver.NO_MAX_SIZE,
+ 50);
+
+ assertThat(d).isInstanceOf(BitmapDrawable.class);
+ BitmapDrawable bd = (BitmapDrawable) d;
+ assertThat(bd.getBitmap().getWidth()).isGreaterThan(101);
+ assertThat(bd.getBitmap().getHeight()).isGreaterThan(51);
+ }
+
+ @Test
public void resolveImage_largeBitmapIcon_passedSize_resizeToDefinedSize() {
Icon icon = Icon.createWithBitmap(
BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index a9730785723b..472741653d9e 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -296,6 +296,8 @@ applications that come with the platform
<permission name="android.permission.MANAGE_LOW_POWER_STANDBY" />
<permission name="android.permission.MANAGE_ROLLBACKS"/>
<permission name="android.permission.MANAGE_USB"/>
+ <!-- Needed for tests only -->
+ <permission name="android.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION" />
<permission name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
<permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
@@ -500,7 +502,6 @@ applications that come with the platform
<!-- Permissions required for CTS test - CtsSafetyCenterTestCases -->
<permission name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
<permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
- <permission name="android.permission.SEND_LOST_MODE_LOCATION_UPDATES" />
<!-- Permission required for CTS test - CtsTelephonyTestCases -->
<permission name="android.permission.BIND_TELECOM_CONNECTION_SERVICE" />
</privapp-permissions>
diff --git a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
index fb0880ce3521..bbaf0862f923 100644
--- a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
+++ b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
@@ -19,7 +19,10 @@ package android.security.identity;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.os.RemoteException;
import android.os.ServiceManager;
+import android.security.GenerateRkpKey;
+import android.security.keymaster.KeymasterDefs;
class CredstoreIdentityCredentialStore extends IdentityCredentialStore {
@@ -104,6 +107,16 @@ class CredstoreIdentityCredentialStore extends IdentityCredentialStore {
try {
IWritableCredential wc;
wc = mStore.createCredential(credentialName, docType);
+ try {
+ GenerateRkpKey keyGen = new GenerateRkpKey(mContext);
+ // We don't know what the security level is for the backing keymint, so go ahead and
+ // poke the provisioner for both TEE and SB.
+ keyGen.notifyKeyGenerated(KeymasterDefs.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
+ keyGen.notifyKeyGenerated(KeymasterDefs.KM_SECURITY_LEVEL_STRONGBOX);
+ } catch (RemoteException e) {
+ // Not really an error state. Does not apply at all if RKP is unsupported or
+ // disabled on a given device.
+ }
return new CredstoreWritableIdentityCredential(mContext, credentialName, docType, wc);
} catch (android.os.RemoteException e) {
throw new RuntimeException("Unexpected RemoteException ", e);
diff --git a/keystore/java/android/security/KeyStoreException.java b/keystore/java/android/security/KeyStoreException.java
index 54184dbf6e08..1a81dda8d56c 100644
--- a/keystore/java/android/security/KeyStoreException.java
+++ b/keystore/java/android/security/KeyStoreException.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.annotation.TestApi;
import android.security.keymaster.KeymasterDefs;
import android.system.keystore2.ResponseCode;
+import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -36,6 +37,8 @@ import java.util.Map;
* is likely to succeed.
*/
public class KeyStoreException extends Exception {
+ private static final String TAG = "KeyStoreException";
+
/**
* This error code is for mapping errors that the caller will not know about. If the caller is
* targeting an API level earlier than the one the error was introduced in, then the error will
@@ -114,6 +117,27 @@ public class KeyStoreException extends Exception {
* The caller should re-create the crypto object and try again.
*/
public static final int ERROR_KEY_OPERATION_EXPIRED = 15;
+ /**
+ * There are no keys available for attestation.
+ * This error is returned only on devices that rely solely on remotely-provisioned keys (see
+ * <a href=
+ * "https://android-developers.googleblog.com/2022/03/upgrading-android-attestation-remote.html"
+ * >Remote Key Provisioning</a>).
+ *
+ * <p>On such a device, if the caller requests key generation and includes an attestation
+ * challenge (indicating key attestation is required), the error will be returned in one of
+ * the following cases:
+ * <ul>
+ * <li>The pool of remotely-provisioned keys has been exhausted.</li>
+ * <li>The device is not registered with the key provisioning server.</li>
+ * </ul>
+ * </p>
+ *
+ * <p>This error is a transient one if the pool of remotely-provisioned keys has been
+ * exhausted. However, if the device is not registered with the server, or the key
+ * provisioning server refuses key issuance, this is a permanent error.</p>
+ */
+ public static final int ERROR_ATTESTATION_KEYS_UNAVAILABLE = 16;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -132,11 +156,68 @@ public class KeyStoreException extends Exception {
ERROR_UNIMPLEMENTED,
ERROR_INCORRECT_USAGE,
ERROR_KEY_NOT_TEMPORALLY_VALID,
- ERROR_KEY_OPERATION_EXPIRED
+ ERROR_KEY_OPERATION_EXPIRED,
+ ERROR_ATTESTATION_KEYS_UNAVAILABLE
})
public @interface PublicErrorCode {
}
+ /**
+ * Never re-try the operation that led to this error, since it's a permanent error.
+ *
+ * This value is always returned when {@link #isTransientFailure()} is {@code false}.
+ */
+ public static final int RETRY_NEVER = 1;
+ /**
+ * Re-try the operation that led to this error with an exponential back-off delay.
+ * The first delay should be between 5 to 30 seconds, and each subsequent re-try should double
+ * the delay time.
+ *
+ * This value is returned when {@link #isTransientFailure()} is {@code true}.
+ */
+ public static final int RETRY_WITH_EXPONENTIAL_BACKOFF = 2;
+ /**
+ * Re-try the operation that led to this error when the device regains connectivity.
+ * Remote provisioning of keys requires reaching the remote server, and the device is
+ * currently unable to due that due to lack of network connectivity.
+ *
+ * This value is returned when {@link #isTransientFailure()} is {@code true}.
+ */
+ public static final int RETRY_WHEN_CONNECTIVITY_AVAILABLE = 3;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = {"RETRY_"}, value = {
+ RETRY_NEVER,
+ RETRY_WITH_EXPONENTIAL_BACKOFF,
+ RETRY_WHEN_CONNECTIVITY_AVAILABLE,
+ })
+ public @interface RetryPolicy {
+ }
+
+ // RKP-specific error information.
+ /**
+ * Remote provisioning of attestation keys has completed successfully.
+ * @hide */
+ public static final int RKP_SUCCESS = 0;
+ /**
+ * Remotely-provisioned keys are temporarily unavailable. This could be because of RPC
+ * error when talking to the remote provisioner or keys are being currently fetched and will
+ * be available soon.
+ * @hide */
+ public static final int RKP_TEMPORARILY_UNAVAILABLE = 1;
+ /**
+ * Permanent failure: The RKP server has declined issuance of keys to this device. Either
+ * because the device is not registered with the server or the server considers the device
+ * not to be trustworthy.
+ * @hide */
+ public static final int RKP_SERVER_REFUSED_ISSUANCE = 2;
+ /**
+ * The RKP server is unavailable due to lack of connectivity. The caller should re-try
+ * when the device has connectivity again.
+ * @hide */
+ public static final int RKP_FETCHING_PENDING_CONNECTIVITY = 3;
+
// Constants for encoding information about the error encountered:
// Whether the error relates to the system state/implementation as a whole, or a specific key.
private static final int IS_SYSTEM_ERROR = 1 << 1;
@@ -148,6 +229,21 @@ public class KeyStoreException extends Exception {
// The internal error code. NOT to be returned directly to callers or made part of the
// public API.
private final int mErrorCode;
+ // The Remote Key Provisioning status. Applicable if and only if {@link #mErrorCode} is equal
+ // to {@link ResponseCode.OUT_OF_KEYS}.
+ private final int mRkpStatus;
+
+ private static int initializeRkpStatusForRegularErrors(int errorCode) {
+ // Check if the system code mistakenly called a constructor of KeyStoreException with
+ // the OUT_OF_KEYS error code but without RKP status.
+ if (errorCode == ResponseCode.OUT_OF_KEYS) {
+ Log.e(TAG, "RKP error code without RKP status");
+ // Set RKP status to RKP_SERVER_REFUSED_ISSUANCE so that the caller never retries.
+ return RKP_SERVER_REFUSED_ISSUANCE;
+ } else {
+ return RKP_SUCCESS;
+ }
+ }
/**
* @hide
@@ -155,6 +251,7 @@ public class KeyStoreException extends Exception {
public KeyStoreException(int errorCode, @Nullable String message) {
super(message);
mErrorCode = errorCode;
+ mRkpStatus = initializeRkpStatusForRegularErrors(errorCode);
}
/**
@@ -165,6 +262,19 @@ public class KeyStoreException extends Exception {
super(message + " (internal Keystore code: " + errorCode + " message: "
+ keystoreErrorMessage + ")");
mErrorCode = errorCode;
+ mRkpStatus = initializeRkpStatusForRegularErrors(errorCode);
+ }
+
+ /**
+ * @hide
+ */
+ public KeyStoreException(int errorCode, @Nullable String message, int rkpStatus) {
+ super(message);
+ mErrorCode = errorCode;
+ mRkpStatus = rkpStatus;
+ if (mErrorCode != ResponseCode.OUT_OF_KEYS) {
+ Log.e(TAG, "Providing RKP status for error code " + errorCode + " has no effect.");
+ }
}
/**
@@ -198,6 +308,17 @@ public class KeyStoreException extends Exception {
*/
public boolean isTransientFailure() {
PublicErrorInformation failureInfo = getErrorInformation(mErrorCode);
+ // Special-case handling for RKP failures:
+ if (mRkpStatus != RKP_SUCCESS && mErrorCode == ResponseCode.OUT_OF_KEYS) {
+ switch (mRkpStatus) {
+ case RKP_TEMPORARILY_UNAVAILABLE:
+ case RKP_FETCHING_PENDING_CONNECTIVITY:
+ return true;
+ case RKP_SERVER_REFUSED_ISSUANCE:
+ default:
+ return false;
+ }
+ }
return (failureInfo.indicators & IS_TRANSIENT_ERROR) != 0;
}
@@ -225,6 +346,34 @@ public class KeyStoreException extends Exception {
return (failureInfo.indicators & IS_SYSTEM_ERROR) != 0;
}
+ /**
+ * Returns the re-try policy for transient failures. Valid only if
+ * {@link #isTransientFailure()} returns {@code True}.
+ */
+ @RetryPolicy
+ public int getRetryPolicy() {
+ PublicErrorInformation failureInfo = getErrorInformation(mErrorCode);
+ // Special-case handling for RKP failures:
+ if (mRkpStatus != RKP_SUCCESS) {
+ switch (mRkpStatus) {
+ case RKP_TEMPORARILY_UNAVAILABLE:
+ return RETRY_WITH_EXPONENTIAL_BACKOFF;
+ case RKP_FETCHING_PENDING_CONNECTIVITY:
+ return RETRY_WHEN_CONNECTIVITY_AVAILABLE;
+ case RKP_SERVER_REFUSED_ISSUANCE:
+ return RETRY_NEVER;
+ default:
+ return (failureInfo.indicators & IS_TRANSIENT_ERROR) != 0
+ ? RETRY_WITH_EXPONENTIAL_BACKOFF : RETRY_NEVER;
+ }
+ }
+ if ((failureInfo.indicators & IS_TRANSIENT_ERROR) != 0) {
+ return RETRY_WITH_EXPONENTIAL_BACKOFF;
+ } else {
+ return RETRY_NEVER;
+ }
+ }
+
@Override
public String toString() {
String errorCodes = String.format(" (public error code: %d internal Keystore code: %d)",
@@ -469,5 +618,7 @@ public class KeyStoreException extends Exception {
new PublicErrorInformation(0, ERROR_KEY_CORRUPTED));
sErrorCodeToFailureInfo.put(ResponseCode.KEY_PERMANENTLY_INVALIDATED,
new PublicErrorInformation(0, ERROR_KEY_DOES_NOT_EXIST));
+ sErrorCodeToFailureInfo.put(ResponseCode.OUT_OF_KEYS,
+ new PublicErrorInformation(IS_SYSTEM_ERROR, ERROR_ATTESTATION_KEYS_UNAVAILABLE));
}
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index e7961c94928c..5950b5bc7231 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -28,7 +28,6 @@ import android.hardware.security.keymint.Tag;
import android.os.Build;
import android.os.RemoteException;
import android.security.GenerateRkpKey;
-import android.security.GenerateRkpKeyException;
import android.security.KeyPairGeneratorSpec;
import android.security.KeyStore2;
import android.security.KeyStoreException;
@@ -618,18 +617,44 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
@Override
public KeyPair generateKeyPair() {
- try {
- return generateKeyPairHelper();
- } catch (GenerateRkpKeyException e) {
- try {
- return generateKeyPairHelper();
- } catch (GenerateRkpKeyException f) {
- throw new ProviderException("Failed to provision new attestation keys.");
+ GenerateKeyPairHelperResult result = new GenerateKeyPairHelperResult(0, null);
+ for (int i = 0; i < 2; i++) {
+ /**
+ * NOTE: There is no need to delay between re-tries because the call to
+ * GenerateRkpKey.notifyEmpty() will delay for a while before returning.
+ */
+ result = generateKeyPairHelper();
+ if (result.rkpStatus == KeyStoreException.RKP_SUCCESS) {
+ return result.keyPair;
}
}
+
+ // RKP failure
+ if (result.rkpStatus != KeyStoreException.RKP_SUCCESS) {
+ KeyStoreException ksException = new KeyStoreException(ResponseCode.OUT_OF_KEYS,
+ "Could not get RKP keys", result.rkpStatus);
+ throw new ProviderException("Failed to provision new attestation keys.", ksException);
+ }
+
+ return result.keyPair;
+ }
+
+ private static class GenerateKeyPairHelperResult {
+ // Zero indicates success, non-zero indicates failure. Values should be
+ // {@link android.security.KeyStoreException#RKP_TEMPORARILY_UNAVAILABLE},
+ // {@link android.security.KeyStoreException#RKP_SERVER_REFUSED_ISSUANCE},
+ // {@link android.security.KeyStoreException#RKP_FETCHING_PENDING_CONNECTIVITY}
+ public final int rkpStatus;
+ @Nullable
+ public final KeyPair keyPair;
+
+ private GenerateKeyPairHelperResult(int rkpStatus, KeyPair keyPair) {
+ this.rkpStatus = rkpStatus;
+ this.keyPair = keyPair;
+ }
}
- private KeyPair generateKeyPairHelper() throws GenerateRkpKeyException {
+ private GenerateKeyPairHelperResult generateKeyPairHelper() {
if (mKeyStore == null || mSpec == null) {
throw new IllegalStateException("Not initialized");
}
@@ -679,7 +704,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
Log.d(TAG, "Couldn't connect to the RemoteProvisioner backend.", e);
}
success = true;
- return new KeyPair(publicKey, publicKey.getPrivateKey());
+ KeyPair kp = new KeyPair(publicKey, publicKey.getPrivateKey());
+ return new GenerateKeyPairHelperResult(0, kp);
} catch (android.security.KeyStoreException e) {
switch (e.getErrorCode()) {
case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE:
@@ -688,11 +714,19 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
GenerateRkpKey keyGen = new GenerateRkpKey(ActivityThread
.currentApplication());
try {
+ //TODO: When detailed error information is available from the remote
+ //provisioner, propagate it up.
keyGen.notifyEmpty(securityLevel);
} catch (RemoteException f) {
- throw new ProviderException("Failed to talk to RemoteProvisioner", f);
+ KeyStoreException ksException = new KeyStoreException(
+ ResponseCode.OUT_OF_KEYS,
+ "Remote exception: " + f.getMessage(),
+ KeyStoreException.RKP_TEMPORARILY_UNAVAILABLE);
+ throw new ProviderException("Failed to talk to RemoteProvisioner",
+ ksException);
}
- throw new GenerateRkpKeyException();
+ return new GenerateKeyPairHelperResult(
+ KeyStoreException.RKP_TEMPORARILY_UNAVAILABLE, null);
default:
ProviderException p = new ProviderException("Failed to generate key pair.", e);
if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 418ff0e7263a..bb3b534403bb 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -43,6 +43,8 @@ import android.window.WindowContainerTransaction;
import androidx.window.common.EmptyLifecycleCallbacksAdapter;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -65,10 +67,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
* When the app is host of multiple Tasks, there can be multiple splits controlled by the same
* organizer.
*/
- private final SparseArray<TaskContainer> mTaskContainers = new SparseArray<>();
+ @VisibleForTesting
+ final SparseArray<TaskContainer> mTaskContainers = new SparseArray<>();
// Callback to Jetpack to notify about changes to split states.
- private @NonNull Consumer<List<SplitInfo>> mEmbeddingCallback;
+ @NonNull
+ private Consumer<List<SplitInfo>> mEmbeddingCallback;
private final List<SplitInfo> mLastReportedSplitStates = new ArrayList<>();
// We currently only support split activity embedding within the one root Task.
@@ -1029,7 +1033,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
/** Represents TaskFragments and split pairs below a Task. */
- private static class TaskContainer {
+ @VisibleForTesting
+ static class TaskContainer {
final List<TaskFragmentContainer> mContainers = new ArrayList<>();
final List<SplitContainer> mSplitContainers = new ArrayList<>();
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/Android.bp b/libs/WindowManager/Jetpack/tests/unittest/Android.bp
index 62e8128f9362..212fbd0a6752 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/Android.bp
+++ b/libs/WindowManager/Jetpack/tests/unittest/Android.bp
@@ -46,6 +46,12 @@ android_test {
"android.test.runner",
],
+ // These are not normally accessible from apps so they must be explicitly included.
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
+
optimize: {
enabled: false,
},
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
new file mode 100644
index 000000000000..30e89a6524c7
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 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 androidx.window.extensions.embedding;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.window.extensions.embedding.SplitController.TaskContainer;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SplitControllerTest {
+ private static final int TASK_ID = 10;
+
+ private SplitController mSplitController;
+
+ @Before
+ public void setUp() {
+ mSplitController = new SplitController();
+ spyOn(mSplitController);
+ }
+
+ @Test
+ public void testGetTopActiveContainer() {
+ TaskContainer taskContainer = new TaskContainer();
+ // tf3 is finished so is not active.
+ TaskFragmentContainer tf3 = mock(TaskFragmentContainer.class);
+ doReturn(true).when(tf3).isFinished();
+ // tf2 has running activity so is active.
+ TaskFragmentContainer tf2 = mock(TaskFragmentContainer.class);
+ doReturn(1).when(tf2).getRunningActivityCount();
+ // tf1 has no running activity so is not active.
+ TaskFragmentContainer tf1 = new TaskFragmentContainer(null, TASK_ID);
+
+ taskContainer.mContainers.add(tf3);
+ taskContainer.mContainers.add(tf2);
+ taskContainer.mContainers.add(tf1);
+ mSplitController.mTaskContainers.put(TASK_ID, taskContainer);
+
+ assertWithMessage("Must return tf2 because tf3 is not active.")
+ .that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf2);
+
+ taskContainer.mContainers.remove(tf1);
+
+ assertWithMessage("Must return tf2 because tf2 has running activity.")
+ .that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf2);
+
+ taskContainer.mContainers.remove(tf2);
+
+ assertWithMessage("Must return null because tf1 has no running activity.")
+ .that(mSplitController.getTopActiveContainer(TASK_ID)).isNull();
+ }
+}
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index e9b3c4990ef2..7960dec5080b 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -140,6 +140,11 @@ android_library {
"dagger2",
"jsr330",
],
+ libs: [
+ // Soong fails to automatically add this dependency because all the
+ // *.kt sources are inside a filegroup.
+ "kotlin-annotations",
+ ],
kotlincflags: ["-Xjvm-default=enable"],
manifest: "AndroidManifest.xml",
plugins: ["dagger2-compiler"],
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 59d03c738723..a2f9e884b37d 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -74,6 +74,10 @@
<!-- PIP stash offset size, which is the width of visible PIP region when stashed. -->
<dimen name="pip_stash_offset">32dp</dimen>
+ <!-- PIP shadow radius, originally as
+ WindowConfiguration#PINNED_WINDOWING_MODE_ELEVATION_IN_DIP -->
+ <dimen name="pip_shadow_radius">5dp</dimen>
+
<dimen name="dismiss_target_x_size">24dp</dimen>
<dimen name="floating_dismiss_bottom_margin">50dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
index 8483f070d06a..06f4367752fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
@@ -119,8 +119,6 @@ public final class ShellCommandHandlerImpl {
return runRemoveFromSideStage(args, pw);
case "setSideStagePosition":
return runSetSideStagePosition(args, pw);
- case "setSideStageVisibility":
- return runSetSideStageVisibility(args, pw);
case "help":
return runHelp(pw);
default:
@@ -186,18 +184,6 @@ public final class ShellCommandHandlerImpl {
return true;
}
- private boolean runSetSideStageVisibility(String[] args, PrintWriter pw) {
- if (args.length < 3) {
- // First arguments are "WMShell" and command name.
- pw.println("Error: side stage visibility should be provided as arguments");
- return false;
- }
- final Boolean visible = new Boolean(args[2]);
-
- mSplitScreenOptional.ifPresent(split -> split.setSideStageVisibility(visible));
- return true;
- }
-
private boolean runHelp(PrintWriter pw) {
pw.println("Window Manager Shell commands:");
pw.println(" help");
@@ -215,8 +201,6 @@ public final class ShellCommandHandlerImpl {
pw.println(" Enable/Disable outline on the side-stage.");
pw.println(" setSideStagePosition <SideStagePosition>");
pw.println(" Sets the position of the side-stage.");
- pw.println(" setSideStageVisibility <true/false>");
- pw.println(" Show/hide side-stage.");
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt
index 255e4d2c0d44..4b7950e9090a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt
@@ -19,7 +19,6 @@ package com.android.wm.shell.animation
import android.util.ArrayMap
import android.util.Log
import android.view.View
-import androidx.dynamicanimation.animation.AnimationHandler
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.FlingAnimation
import androidx.dynamicanimation.animation.FloatPropertyCompat
@@ -124,12 +123,6 @@ class PhysicsAnimator<T> private constructor (target: T) {
private var defaultFling: FlingConfig = globalDefaultFling
/**
- * AnimationHandler to use if it need custom AnimationHandler, if this is null, it will use
- * the default AnimationHandler in the DynamicAnimation.
- */
- private var customAnimationHandler: AnimationHandler? = null
-
- /**
* Internal listeners that respond to DynamicAnimations updating and ending, and dispatch to
* the listeners provided via [addUpdateListener] and [addEndListener]. This allows us to add
* just one permanent update and end listener to the DynamicAnimations.
@@ -453,14 +446,6 @@ class PhysicsAnimator<T> private constructor (target: T) {
this.defaultFling = defaultFling
}
- /**
- * Set the custom AnimationHandler for all aniatmion in this animator. Set this with null for
- * restoring to default AnimationHandler.
- */
- fun setCustomAnimationHandler(handler: AnimationHandler) {
- this.customAnimationHandler = handler
- }
-
/** Starts the animations! */
fun start() {
startAction()
@@ -510,13 +495,10 @@ class PhysicsAnimator<T> private constructor (target: T) {
// springs) on this property before flinging.
cancel(animatedProperty)
- // Apply the custom animation handler if it not null
- val flingAnim = getFlingAnimation(animatedProperty, target)
- flingAnim.animationHandler =
- customAnimationHandler ?: flingAnim.animationHandler
-
// Apply the configuration and start the animation.
- flingAnim.also { flingConfig.applyToAnimation(it) }.start()
+ getFlingAnimation(animatedProperty, target)
+ .also { flingConfig.applyToAnimation(it) }
+ .start()
}
}
@@ -528,21 +510,6 @@ class PhysicsAnimator<T> private constructor (target: T) {
if (flingConfig == null) {
// Apply the configuration and start the animation.
val springAnim = getSpringAnimation(animatedProperty, target)
-
- // If customAnimationHander is exist and has not been set to the animation,
- // it should set here.
- if (customAnimationHandler != null &&
- springAnim.animationHandler != customAnimationHandler) {
- // Cancel the animation before set animation handler
- if (springAnim.isRunning) {
- cancel(animatedProperty)
- }
- // Apply the custom animation handler if it not null
- springAnim.animationHandler =
- customAnimationHandler ?: springAnim.animationHandler
- }
-
- // Apply the configuration and start the animation.
springConfig.applyToAnimation(springAnim)
animationStartActions.add(springAnim::start)
} else {
@@ -597,13 +564,10 @@ class PhysicsAnimator<T> private constructor (target: T) {
}
}
- // Apply the custom animation handler if it not null
- val springAnim = getSpringAnimation(animatedProperty, target)
- springAnim.animationHandler =
- customAnimationHandler ?: springAnim.animationHandler
-
// Apply the configuration and start the spring animation.
- springAnim.also { springConfig.applyToAnimation(it) }.start()
+ getSpringAnimation(animatedProperty, target)
+ .also { springConfig.applyToAnimation(it) }
+ .start()
}
}
})
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
index 33eec335bca3..e528df8c89b4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
@@ -19,7 +19,6 @@ package com.android.wm.shell.apppairs;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -83,7 +82,7 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou
public void onLeashReady(SurfaceControl leash) {
mSyncQueue.runInSync(t -> t
.show(leash)
- .setLayer(leash, SPLIT_DIVIDER_LAYER)
+ .setLayer(leash, Integer.MAX_VALUE)
.setPosition(leash,
mSplitLayout.getDividerBounds().left,
mSplitLayout.getDividerBounds().top));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
index 7cf359729ee8..e71a59d26740 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.back;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.window.BackEvent;
@@ -29,8 +30,14 @@ public interface BackAnimation {
/**
* Called when a {@link MotionEvent} is generated by a back gesture.
+ *
+ * @param event the original {@link MotionEvent}
+ * @param action the original {@link KeyEvent#getAction()} when the event was dispatched to
+ * the process. This is forwarded separately because the input pipeline may mutate
+ * the {#event} action state later.
+ * @param swipeEdge the edge from which the swipe begins.
*/
- void onBackMotion(MotionEvent event, @BackEvent.SwipeEdge int swipeEdge);
+ void onBackMotion(MotionEvent event, int action, @BackEvent.SwipeEdge int swipeEdge);
/**
* Sets whether the back gesture is past the trigger threshold or not.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 08cb252cdf43..93ee3f5378e8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -138,8 +138,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
@Override
- public void onBackMotion(MotionEvent event, @BackEvent.SwipeEdge int swipeEdge) {
- mShellExecutor.execute(() -> onMotionEvent(event, swipeEdge));
+ public void onBackMotion(
+ MotionEvent event, int action, @BackEvent.SwipeEdge int swipeEdge) {
+ mShellExecutor.execute(() -> onMotionEvent(event, action, swipeEdge));
}
@Override
@@ -209,13 +210,13 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
* Called when a new motion event needs to be transferred to this
* {@link BackAnimationController}
*/
- public void onMotionEvent(MotionEvent event, @BackEvent.SwipeEdge int swipeEdge) {
- int action = event.getActionMasked();
+ public void onMotionEvent(MotionEvent event, int action, @BackEvent.SwipeEdge int swipeEdge) {
if (action == MotionEvent.ACTION_DOWN) {
initAnimation(event);
} else if (action == MotionEvent.ACTION_MOVE) {
onMove(event, swipeEdge);
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Finishing gesture with event: %s", event);
onGestureFinished();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index d2a1c55d1c29..80afdee2283a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -530,7 +530,8 @@ public class BubbleController {
}
}
- private void onStatusBarStateChanged(boolean isShade) {
+ @VisibleForTesting
+ public void onStatusBarStateChanged(boolean isShade) {
mIsStatusBarShade = isShade;
if (!mIsStatusBarShade) {
collapseStack();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index 3ac7cbfe9c2e..5dc6bd19853a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -21,7 +21,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -162,7 +161,7 @@ public class SplitDecorManager extends WindowlessWindowManager {
mBackgroundLeash = SurfaceUtils.makeColorLayer(mHostLeash,
RESIZING_BACKGROUND_SURFACE_NAME, mSurfaceSession);
t.setColor(mBackgroundLeash, getResizingBackgroundColor(resizingTask))
- .setLayer(mBackgroundLeash, SPLIT_DIVIDER_LAYER - 1);
+ .setLayer(mBackgroundLeash, Integer.MAX_VALUE - 1);
}
if (mIcon == null && resizingTask.topActivityInfo != null) {
@@ -175,7 +174,7 @@ public class SplitDecorManager extends WindowlessWindowManager {
lp.width = mIcon.getIntrinsicWidth();
lp.height = mIcon.getIntrinsicHeight();
mViewHost.relayout(lp);
- t.setLayer(mIconLeash, SPLIT_DIVIDER_LAYER);
+ t.setLayer(mIconLeash, Integer.MAX_VALUE);
}
t.setPosition(mIconLeash,
newBounds.width() / 2 - mIcon.getIntrinsicWidth() / 2,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index d05a4df2a4cc..116d3524e711 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -23,7 +23,6 @@ import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;
-import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END;
import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START;
@@ -202,24 +201,24 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
/** Applies new configuration, returns {@code false} if there's no effect to the layout. */
public boolean updateConfiguration(Configuration configuration) {
+ // Always update configuration after orientation changed to make sure to render divider bar
+ // with proper resources that matching screen orientation.
+ final int orientation = configuration.orientation;
+ if (mOrientation != orientation) {
+ mContext = mContext.createConfigurationContext(configuration);
+ mSplitWindowManager.setConfiguration(configuration);
+ mOrientation = orientation;
+ }
+
// Update the split bounds when necessary. Besides root bounds changed, split bounds need to
// be updated when the rotation changed to cover the case that users rotated the screen 180
// degrees.
- // Make sure to render the divider bar with proper resources that matching the screen
- // orientation.
final int rotation = configuration.windowConfiguration.getRotation();
final Rect rootBounds = configuration.windowConfiguration.getBounds();
- final int orientation = configuration.orientation;
-
- if (mOrientation == orientation
- && rotation == mRotation
- && mRootBounds.equals(rootBounds)) {
+ if (mRotation == rotation && mRootBounds.equals(rootBounds)) {
return false;
}
- mContext = mContext.createConfigurationContext(configuration);
- mSplitWindowManager.setConfiguration(configuration);
- mOrientation = orientation;
mTempRect.set(mRootBounds);
mRootBounds.set(rootBounds);
mRotation = rotation;
@@ -493,7 +492,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
mTempRect.set(getRefDividerBounds());
t.setPosition(dividerLeash, mTempRect.left, mTempRect.top);
// Resets layer of divider bar to make sure it is always on top.
- t.setLayer(dividerLeash, SPLIT_DIVIDER_LAYER);
+ t.setLayer(dividerLeash, Integer.MAX_VALUE);
}
mTempRect.set(getRefBounds1());
t.setPosition(leash1, mTempRect.left, mTempRect.top)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
index ef627647794e..062e3ba26356 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
@@ -26,12 +26,13 @@ oneway interface IPipAnimationListener {
void onPipAnimationStarted();
/**
- * Notifies the listener about PiP round corner radius changes.
+ * Notifies the listener about PiP resource dimensions changed.
* Listener can expect an immediate callback the first time they attach.
*
* @param cornerRadius the pixel value of the corner radius, zero means it's disabled.
+ * @param shadowRadius the pixel value of the shadow radius, zero means it's disabled.
*/
- void onPipCornerRadiusChanged(int cornerRadius);
+ void onPipResourceDimensionsChanged(int cornerRadius, int shadowRadius);
/**
* Notifies the listener that user leaves PiP by tapping on the expand button.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 77fd228af286..51e229e13284 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -30,7 +30,6 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Rect;
-import android.view.Choreographer;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -273,14 +272,15 @@ public class PipAnimationController {
mStartingAngle = startingAngle;
addListener(this);
addUpdateListener(this);
- mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
+ mSurfaceControlTransactionFactory =
+ new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
mTransitionDirection = TRANSITION_DIRECTION_NONE;
}
@Override
public void onAnimationStart(Animator animation) {
mCurrentValue = mStartValue;
- onStartTransaction(mLeash, newSurfaceControlTransaction());
+ onStartTransaction(mLeash, mSurfaceControlTransactionFactory.getTransaction());
if (mPipAnimationCallback != null) {
mPipAnimationCallback.onPipAnimationStart(mTaskInfo, this);
}
@@ -288,14 +288,16 @@ public class PipAnimationController {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
- applySurfaceControlTransaction(mLeash, newSurfaceControlTransaction(),
+ applySurfaceControlTransaction(mLeash,
+ mSurfaceControlTransactionFactory.getTransaction(),
animation.getAnimatedFraction());
}
@Override
public void onAnimationEnd(Animator animation) {
mCurrentValue = mEndValue;
- final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
+ final SurfaceControl.Transaction tx =
+ mSurfaceControlTransactionFactory.getTransaction();
onEndTransaction(mLeash, tx, mTransitionDirection);
if (mPipAnimationCallback != null) {
mPipAnimationCallback.onPipAnimationEnd(mTaskInfo, tx, this);
@@ -342,7 +344,8 @@ public class PipAnimationController {
}
PipTransitionAnimator<T> setUseContentOverlay(Context context) {
- final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
+ final SurfaceControl.Transaction tx =
+ mSurfaceControlTransactionFactory.getTransaction();
if (mContentOverlay != null) {
// remove existing content overlay if there is any.
tx.remove(mContentOverlay);
@@ -417,7 +420,7 @@ public class PipAnimationController {
void setDestinationBounds(Rect destinationBounds) {
mDestinationBounds.set(destinationBounds);
if (mAnimationType == ANIM_TYPE_ALPHA) {
- onStartTransaction(mLeash, newSurfaceControlTransaction());
+ onStartTransaction(mLeash, mSurfaceControlTransactionFactory.getTransaction());
}
}
@@ -447,16 +450,6 @@ public class PipAnimationController {
mEndValue = endValue;
}
- /**
- * @return {@link SurfaceControl.Transaction} instance with vsync-id.
- */
- protected SurfaceControl.Transaction newSurfaceControlTransaction() {
- final SurfaceControl.Transaction tx =
- mSurfaceControlTransactionFactory.getTransaction();
- tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
- return tx;
- }
-
@VisibleForTesting
public void setSurfaceControlTransactionFactory(
PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) {
@@ -489,7 +482,8 @@ public class PipAnimationController {
final float alpha = getStartValue() * (1 - fraction) + getEndValue() * fraction;
setCurrentValue(alpha);
getSurfaceTransactionHelper().alpha(tx, leash, alpha)
- .round(tx, leash, shouldApplyCornerRadius());
+ .round(tx, leash, shouldApplyCornerRadius())
+ .shadow(tx, leash);
tx.apply();
}
@@ -502,7 +496,8 @@ public class PipAnimationController {
getSurfaceTransactionHelper()
.resetScale(tx, leash, getDestinationBounds())
.crop(tx, leash, getDestinationBounds())
- .round(tx, leash, shouldApplyCornerRadius());
+ .round(tx, leash, shouldApplyCornerRadius())
+ .shadow(tx, leash);
tx.show(leash);
tx.apply();
}
@@ -589,7 +584,8 @@ public class PipAnimationController {
} else {
getSurfaceTransactionHelper().crop(tx, leash, base)
.scale(tx, leash, base, bounds, angle)
- .round(tx, leash, base, bounds);
+ .round(tx, leash, base, bounds)
+ .shadow(tx, leash);
}
} else {
final Rect insets = computeInsets(fraction);
@@ -598,8 +594,9 @@ public class PipAnimationController {
if (shouldApplyCornerRadius()) {
final Rect sourceBounds = new Rect(initialContainerRect);
sourceBounds.inset(insets);
- getSurfaceTransactionHelper().round(tx, leash,
- sourceBounds, bounds);
+ getSurfaceTransactionHelper()
+ .round(tx, leash, sourceBounds, bounds)
+ .shadow(tx, leash);
}
}
if (!handlePipTransaction(leash, tx, bounds)) {
@@ -650,7 +647,9 @@ public class PipAnimationController {
insets, degree, x, y, isOutPipDirection,
rotationDelta == ROTATION_270 /* clockwise */);
if (shouldApplyCornerRadius()) {
- getSurfaceTransactionHelper().round(tx, leash, sourceBounds, bounds);
+ getSurfaceTransactionHelper()
+ .round(tx, leash, sourceBounds, bounds)
+ .shadow(tx, leash);
}
tx.apply();
}
@@ -668,7 +667,8 @@ public class PipAnimationController {
void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
getSurfaceTransactionHelper()
.alpha(tx, leash, 1f)
- .round(tx, leash, shouldApplyCornerRadius());
+ .round(tx, leash, shouldApplyCornerRadius())
+ .shadow(tx, leash);
// TODO(b/178632364): this is a work around for the black background when
// entering PiP in buttion navigation mode.
if (isInPipDirection(direction)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
index d7322ce7beda..7447fb54d636 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.view.Choreographer;
import android.view.SurfaceControl;
import com.android.wm.shell.R;
@@ -37,6 +38,7 @@ public class PipSurfaceTransactionHelper {
private final Rect mTmpDestinationRect = new Rect();
private int mCornerRadius;
+ private int mShadowRadius;
/**
* Called when display size or font size of settings changed
@@ -45,6 +47,7 @@ public class PipSurfaceTransactionHelper {
*/
public void onDensityOrFontScaleChanged(Context context) {
mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
+ mShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius);
}
/**
@@ -200,18 +203,29 @@ public class PipSurfaceTransactionHelper {
}
/**
- * Re-parents the snapshot to the parent's surface control and shows it.
+ * Operates the shadow radius on a given transaction and leash
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
*/
- public PipSurfaceTransactionHelper reparentAndShowSurfaceSnapshot(
- SurfaceControl.Transaction t, SurfaceControl parent, SurfaceControl snapshot) {
- t.reparent(snapshot, parent);
- t.setLayer(snapshot, Integer.MAX_VALUE);
- t.show(snapshot);
- t.apply();
+ public PipSurfaceTransactionHelper shadow(SurfaceControl.Transaction tx, SurfaceControl leash) {
+ tx.setShadowRadius(leash, mShadowRadius);
return this;
}
public interface SurfaceControlTransactionFactory {
SurfaceControl.Transaction getTransaction();
}
+
+ /**
+ * Implementation of {@link SurfaceControlTransactionFactory} that returns
+ * {@link SurfaceControl.Transaction} with VsyncId being set.
+ */
+ public static class VsyncSurfaceControlTransactionFactory
+ implements SurfaceControlTransactionFactory {
+ @Override
+ public SurfaceControl.Transaction getTransaction() {
+ final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+ tx.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
+ return tx;
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 5d6b041f9006..da53ca55122b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -280,7 +280,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mSurfaceTransactionHelper = surfaceTransactionHelper;
mPipAnimationController = pipAnimationController;
mPipUiEventLoggerLogger = pipUiEventLogger;
- mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
+ mSurfaceControlTransactionFactory =
+ new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
mSplitScreenOptional = splitScreenOptional;
mTaskOrganizer = shellTaskOrganizer;
mMainExecutor = mainExecutor;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index ad5d85cc083a..623ef05ec7e2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -131,12 +131,13 @@ public class PipController implements PipTransitionController.PipTransitionCallb
void onPipAnimationStarted();
/**
- * Notifies the listener about PiP round corner radius changes.
+ * Notifies the listener about PiP resource dimensions changed.
* Listener can expect an immediate callback the first time they attach.
*
* @param cornerRadius the pixel value of the corner radius, zero means it's disabled.
+ * @param shadowRadius the pixel value of the shadow radius, zero means it's disabled.
*/
- void onPipCornerRadiusChanged(int cornerRadius);
+ void onPipResourceDimensionsChanged(int cornerRadius, int shadowRadius);
/**
* Notifies the listener that user leaves PiP by tapping on the expand button.
@@ -479,7 +480,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
private void onDensityOrFontScaleChanged() {
mPipTaskOrganizer.onDensityOrFontScaleChanged(mContext);
- onPipCornerRadiusChanged();
+ onPipResourceDimensionsChanged();
}
private void onOverlayChanged() {
@@ -590,14 +591,14 @@ public class PipController implements PipTransitionController.PipTransitionCallb
private void setPinnedStackAnimationListener(PipAnimationListener callback) {
mPinnedStackAnimationRecentsCallback = callback;
- onPipCornerRadiusChanged();
+ onPipResourceDimensionsChanged();
}
- private void onPipCornerRadiusChanged() {
+ private void onPipResourceDimensionsChanged() {
if (mPinnedStackAnimationRecentsCallback != null) {
- final int cornerRadius =
- mContext.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
- mPinnedStackAnimationRecentsCallback.onPipCornerRadiusChanged(cornerRadius);
+ mPinnedStackAnimationRecentsCallback.onPipResourceDimensionsChanged(
+ mContext.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius),
+ mContext.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius));
}
}
@@ -916,8 +917,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb
}
@Override
- public void onPipCornerRadiusChanged(int cornerRadius) {
- mListener.call(l -> l.onPipCornerRadiusChanged(cornerRadius));
+ public void onPipResourceDimensionsChanged(int cornerRadius, int shadowRadius) {
+ mListener.call(l -> l.onPipResourceDimensionsChanged(cornerRadius, shadowRadius));
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
index 0f3ff36601fb..5ddb534b6829 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
@@ -146,11 +146,10 @@ public class PipInputConsumer {
"%s: Failed to create input consumer, %s", TAG, e);
}
mMainExecutor.execute(() -> {
- // Choreographer.getSfInstance() must be called on the thread that the input event
+ // Choreographer.getInstance() must be called on the thread that the input event
// receiver should be receiving events
- // TODO(b/222697646): remove getSfInstance usage and use vsyncId for transactions
mInputEventReceiver = new InputEventReceiver(inputChannel,
- Looper.myLooper(), Choreographer.getSfInstance());
+ Looper.myLooper(), Choreographer.getInstance());
if (mRegistrationListener != null) {
mRegistrationListener.onRegistrationChanged(true /* isRegistered */);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index fa0f0925a08a..7028f9a25fbe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -33,11 +33,6 @@ import android.content.Context;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Debug;
-import android.os.Looper;
-import android.view.Choreographer;
-
-import androidx.dynamicanimation.animation.AnimationHandler;
-import androidx.dynamicanimation.animation.AnimationHandler.FrameCallbackScheduler;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
@@ -89,26 +84,6 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
/** Coordinator instance for resolving conflicts with other floating content. */
private FloatingContentCoordinator mFloatingContentCoordinator;
- private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
- ThreadLocal.withInitial(() -> {
- final Looper initialLooper = Looper.myLooper();
- final FrameCallbackScheduler scheduler = new FrameCallbackScheduler() {
- @Override
- public void postFrameCallback(@androidx.annotation.NonNull Runnable runnable) {
- // TODO(b/222697646): remove getSfInstance usage and use vsyncId for
- // transactions
- Choreographer.getSfInstance().postFrameCallback(t -> runnable.run());
- }
-
- @Override
- public boolean isCurrentThread() {
- return Looper.myLooper() == initialLooper;
- }
- };
- AnimationHandler handler = new AnimationHandler(scheduler);
- return handler;
- });
-
/**
* PhysicsAnimator instance for animating {@link PipBoundsState#getMotionBoundsState()}
* using physics animations.
@@ -211,11 +186,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
}
public void init() {
- // Note: Needs to get the shell main thread sf vsync animation handler
mTemporaryBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
mPipBoundsState.getMotionBoundsState().getBoundsInMotion());
- mTemporaryBoundsPhysicsAnimator.setCustomAnimationHandler(
- mSfAnimationHandlerThreadLocal.get());
}
@NonNull
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index abf1a9500e6d..89d85e4b292d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -625,8 +625,7 @@ public class PipResizeGestureHandler {
class PipResizeInputEventReceiver extends BatchedInputEventReceiver {
PipResizeInputEventReceiver(InputChannel channel, Looper looper) {
- // TODO(b/222697646): remove getSfInstance usage and use vsyncId for transactions
- super(channel, looper, Choreographer.getSfInstance());
+ super(channel, looper, Choreographer.getInstance());
}
public void onInputEvent(InputEvent event) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
index 13137faa529f..9adf1961ebf5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
@@ -42,11 +42,6 @@ interface ISplitScreen {
oneway void unregisterSplitScreenListener(in ISplitScreenListener listener) = 2;
/**
- * Hides the side-stage if it is currently visible.
- */
- oneway void setSideStageVisibility(boolean visible) = 3;
-
- /**
* Removes a task from the side stage.
*/
oneway void removeFromSideStage(int taskId) = 4;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
index 22dd9b953be7..ae5e075c4d3f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
@@ -52,9 +52,6 @@ class MainStage extends StageTaskListener {
if (mIsActive) return;
final WindowContainerToken rootToken = mRootTaskInfo.token;
- // Moving the root task to top after the child tasks were re-parented , or the root
- // task cannot be visible and focused.
- wct.reorder(rootToken, true /* onTop */);
if (includingTopTask) {
wct.reparentTasks(
null /* currentParent */,
@@ -83,9 +80,6 @@ class MainStage extends StageTaskListener {
null /* newParent */,
CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE,
CONTROLLED_ACTIVITY_TYPES,
- toTop)
- // We want this re-order to the bottom regardless since we are re-parenting
- // all its tasks.
- .reorder(rootToken, false /* onTop */);
+ toTop);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
index 122fc9f5f780..d55619f5e5ed 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
@@ -45,9 +45,6 @@ class SideStage extends StageTaskListener {
}
boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
- // No matter if the root task is empty or not, moving the root to bottom because it no
- // longer preserves visible child task.
- wct.reorder(mRootTaskInfo.token, false /* onTop */);
if (mChildrenTaskInfo.size() == 0) return false;
wct.reparentTasks(
mRootTaskInfo.token,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitDecorManager.java
deleted file mode 100644
index 8e5cc6d47edd..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitDecorManager.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.splitscreen;
-
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Color;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Binder;
-import android.view.IWindow;
-import android.view.LayoutInflater;
-import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
-import android.view.SurfaceSession;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowlessWindowManager;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import com.android.launcher3.icons.IconProvider;
-import com.android.wm.shell.R;
-import com.android.wm.shell.common.SurfaceUtils;
-
-/**
- * Handles split decor like showing resizing hint for a specific split.
- */
-class SplitDecorManager extends WindowlessWindowManager {
- private static final String TAG = SplitDecorManager.class.getSimpleName();
- private static final String RESIZING_BACKGROUND_SURFACE_NAME = "ResizingBackground";
-
- private final IconProvider mIconProvider;
- private final SurfaceSession mSurfaceSession;
-
- private Drawable mIcon;
- private ImageView mResizingIconView;
- private SurfaceControlViewHost mViewHost;
- private SurfaceControl mHostLeash;
- private SurfaceControl mIconLeash;
- private SurfaceControl mBackgroundLeash;
-
- SplitDecorManager(Configuration configuration, IconProvider iconProvider,
- SurfaceSession surfaceSession) {
- super(configuration, null /* rootSurface */, null /* hostInputToken */);
- mIconProvider = iconProvider;
- mSurfaceSession = surfaceSession;
- }
-
- @Override
- protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
- // Can't set position for the ViewRootImpl SC directly. Create a leash to manipulate later.
- final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
- .setContainerLayer()
- .setName(TAG)
- .setHidden(true)
- .setParent(mHostLeash)
- .setCallsite("SplitDecorManager#attachToParentSurface");
- mIconLeash = builder.build();
- b.setParent(mIconLeash);
- }
-
- void inflate(Context context, SurfaceControl rootLeash, Rect rootBounds) {
- if (mIconLeash != null && mViewHost != null) {
- return;
- }
-
- context = context.createWindowContext(context.getDisplay(), TYPE_APPLICATION_OVERLAY,
- null /* options */);
- mHostLeash = rootLeash;
- mViewHost = new SurfaceControlViewHost(context, context.getDisplay(), this);
-
- final FrameLayout rootLayout = (FrameLayout) LayoutInflater.from(context)
- .inflate(R.layout.split_decor, null);
- mResizingIconView = rootLayout.findViewById(R.id.split_resizing_icon);
-
- final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- 0 /* width */, 0 /* height */, TYPE_APPLICATION_OVERLAY,
- FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT);
- lp.width = rootBounds.width();
- lp.height = rootBounds.height();
- lp.token = new Binder();
- lp.setTitle(TAG);
- lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
- // TODO(b/189839391): Set INPUT_FEATURE_NO_INPUT_CHANNEL after WM supports
- // TRUSTED_OVERLAY for windowless window without input channel.
- mViewHost.setView(rootLayout, lp);
- }
-
- void release(SurfaceControl.Transaction t) {
- if (mViewHost != null) {
- mViewHost.release();
- mViewHost = null;
- }
- if (mIconLeash != null) {
- t.remove(mIconLeash);
- mIconLeash = null;
- }
- if (mBackgroundLeash != null) {
- t.remove(mBackgroundLeash);
- mBackgroundLeash = null;
- }
- mHostLeash = null;
- mIcon = null;
- mResizingIconView = null;
- }
-
- /** Showing resizing hint. */
- void onResizing(ActivityManager.RunningTaskInfo resizingTask, Rect newBounds,
- SurfaceControl.Transaction t) {
- if (mResizingIconView == null) {
- return;
- }
-
- if (mIcon == null) {
- // TODO: add fade-in animation.
- mBackgroundLeash = SurfaceUtils.makeColorLayer(mHostLeash,
- RESIZING_BACKGROUND_SURFACE_NAME, mSurfaceSession);
- t.setColor(mBackgroundLeash, getResizingBackgroundColor(resizingTask))
- .setLayer(mBackgroundLeash, SPLIT_DIVIDER_LAYER - 1)
- .show(mBackgroundLeash);
-
- mIcon = mIconProvider.getIcon(resizingTask.topActivityInfo);
- mResizingIconView.setImageDrawable(mIcon);
- mResizingIconView.setVisibility(View.VISIBLE);
-
- WindowManager.LayoutParams lp =
- (WindowManager.LayoutParams) mViewHost.getView().getLayoutParams();
- lp.width = mIcon.getIntrinsicWidth();
- lp.height = mIcon.getIntrinsicHeight();
- mViewHost.relayout(lp);
- t.show(mIconLeash).setLayer(mIconLeash, SPLIT_DIVIDER_LAYER);
- }
-
- t.setPosition(mIconLeash,
- newBounds.width() / 2 - mIcon.getIntrinsicWidth() / 2,
- newBounds.height() / 2 - mIcon.getIntrinsicWidth() / 2);
- }
-
- /** Stops showing resizing hint. */
- void onResized(Rect newBounds, SurfaceControl.Transaction t) {
- if (mResizingIconView == null) {
- return;
- }
-
- if (mIcon != null) {
- mResizingIconView.setVisibility(View.GONE);
- mResizingIconView.setImageDrawable(null);
- t.remove(mBackgroundLeash).hide(mIconLeash);
- mIcon = null;
- mBackgroundLeash = null;
- }
- }
-
- private static float[] getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) {
- final int taskBgColor = taskInfo.taskDescription.getBackgroundColor();
- return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).getComponents();
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 2da5becae8f5..f20870ff0b2d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -188,7 +188,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
if (mStageCoordinator == null) {
// TODO: Multi-display
mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
- mRootTDAOrganizer, mTaskOrganizer, mDisplayController, mDisplayImeController,
+ mTaskOrganizer, mDisplayController, mDisplayImeController,
mDisplayInsetsController, mTransitions, mTransactionPool, mLogger,
mIconProvider, mRecentTasksOptional, mUnfoldControllerProvider);
}
@@ -239,10 +239,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mStageCoordinator.setSideStagePosition(sideStagePosition, null /* wct */);
}
- public void setSideStageVisibility(boolean visible) {
- mStageCoordinator.setSideStageVisibility(visible);
- }
-
public void enterSplitScreen(int taskId, boolean leftOrTop) {
enterSplitScreen(taskId, leftOrTop, new WindowContainerTransaction());
}
@@ -645,14 +641,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
@Override
- public void setSideStageVisibility(boolean visible) {
- executeRemoteCallWithTaskPermission(mController, "setSideStageVisibility",
- (controller) -> {
- controller.setSideStageVisibility(visible);
- });
- }
-
- @Override
public void removeFromSideStage(int taskId) {
executeRemoteCallWithTaskPermission(mController, "removeFromSideStage",
(controller) -> {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index d30d0cc95f46..cd121ed41fdd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -231,16 +231,6 @@ class SplitScreenTransitions {
void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) {
if (!mAnimations.isEmpty()) return;
- mOnFinish.run();
- if (mFinishTransaction != null) {
- mFinishTransaction.apply();
- mTransactionPool.release(mFinishTransaction);
- mFinishTransaction = null;
- }
- if (mFinishCallback != null) {
- mFinishCallback.onTransitionFinished(wct /* wct */, wctCB /* wctCB */);
- mFinishCallback = null;
- }
if (mAnimatingTransition == mPendingEnter) {
mPendingEnter = null;
}
@@ -248,15 +238,29 @@ class SplitScreenTransitions {
mPendingDismiss = null;
}
if (mAnimatingTransition == mPendingRecent) {
- // If the wct is not null while finishing recent transition, it indicates it's not
- // dismissing split and thus need to reorder split task so they can be on top again.
- final boolean dismissSplit = wct == null;
- mStageCoordinator.finishRecentAnimation(dismissSplit);
+ // If the clean-up wct is null when finishing recent transition, it indicates it's
+ // returning to home and thus no need to reorder tasks.
+ final boolean returnToHome = wct == null;
+ if (returnToHome) {
+ wct = new WindowContainerTransaction();
+ }
+ mStageCoordinator.onRecentTransitionFinished(returnToHome, wct, mFinishTransaction);
mPendingRecent = null;
}
mPendingRemoteHandler = null;
mActiveRemoteHandler = null;
mAnimatingTransition = null;
+
+ mOnFinish.run();
+ if (mFinishTransaction != null) {
+ mFinishTransaction.apply();
+ mTransactionPool.release(mFinishTransaction);
+ mFinishTransaction = null;
+ }
+ if (mFinishCallback != null) {
+ mFinishCallback.onTransitionFinished(wct /* wct */, wctCB /* wctCB */);
+ mFinishCallback = null;
+ }
}
// TODO(shell-transitions): real animations
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 880693de7891..3593eddf4b3b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -28,7 +28,6 @@ import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.transitTypeToString;
-import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -43,6 +42,7 @@ import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DEVICE_FOLDED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_ROOT_TASK_VANISHED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_UNKNOWN;
import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
@@ -53,6 +53,7 @@ import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_P
import static com.android.wm.shell.transition.Transitions.isClosingType;
import static com.android.wm.shell.transition.Transitions.isOpeningType;
+import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -77,7 +78,6 @@ import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.WindowManager;
-import android.window.DisplayAreaInfo;
import android.window.RemoteTransition;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
@@ -88,7 +88,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
import com.android.internal.protolog.common.ProtoLog;
import com.android.launcher3.icons.IconProvider;
-import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
@@ -122,13 +121,13 @@ import javax.inject.Provider;
* - The {@link MainStage} should only have children if the coordinator is active.
* - The {@link SplitLayout} divider is only visible if both the {@link MainStage}
* and {@link SideStage} are visible.
- * - The {@link MainStage} configuration is fullscreen when the {@link SideStage} isn't visible.
+ * - Both stages are put under a single-top root task.
* This rules are mostly implemented in {@link #onStageVisibilityChanged(StageListenerImpl)} and
* {@link #onStageHasChildrenChanged(StageListenerImpl).}
*/
class StageCoordinator implements SplitLayout.SplitLayoutHandler,
- RootTaskDisplayAreaOrganizer.RootTaskDisplayAreaListener,
- DisplayController.OnDisplaysChangedListener, Transitions.TransitionHandler {
+ DisplayController.OnDisplaysChangedListener, Transitions.TransitionHandler,
+ ShellTaskOrganizer.TaskListener {
private static final String TAG = StageCoordinator.class.getSimpleName();
@@ -148,9 +147,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private SplitLayout mSplitLayout;
private boolean mDividerVisible;
private final SyncTransactionQueue mSyncQueue;
- private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
private final ShellTaskOrganizer mTaskOrganizer;
- private DisplayAreaInfo mDisplayAreaInfo;
private final Context mContext;
private final List<SplitScreen.SplitScreenListener> mListeners = new ArrayList<>();
private final DisplayController mDisplayController;
@@ -160,6 +157,15 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private final SplitScreenTransitions mSplitTransitions;
private final SplitscreenEventLogger mLogger;
private final Optional<RecentTasksController> mRecentTasks;
+
+ /**
+ * A single-top root task which the split divider attached to.
+ */
+ @VisibleForTesting
+ ActivityManager.RunningTaskInfo mRootTaskInfo;
+
+ private SurfaceControl mRootTaskLeash;
+
// Tracks whether we should update the recent tasks. Only allow this to happen in between enter
// and exit, since exit itself can trigger a number of changes that update the stages.
private boolean mShouldUpdateRecents;
@@ -174,7 +180,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
new SplitWindowManager.ParentContainerCallbacks() {
@Override
public void attachToParentSurface(SurfaceControl.Builder b) {
- mRootTDAOrganizer.attachToDisplayArea(mDisplayId, b);
+ b.setParent(mRootTaskLeash);
}
@Override
@@ -184,23 +190,21 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
};
StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
- RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
- DisplayController displayController,
+ ShellTaskOrganizer taskOrganizer, DisplayController displayController,
DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController, Transitions transitions,
TransactionPool transactionPool, SplitscreenEventLogger logger,
- IconProvider iconProvider,
- Optional<RecentTasksController> recentTasks,
+ IconProvider iconProvider, Optional<RecentTasksController> recentTasks,
Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
mContext = context;
mDisplayId = displayId;
mSyncQueue = syncQueue;
- mRootTDAOrganizer = rootTDAOrganizer;
mTaskOrganizer = taskOrganizer;
mLogger = logger;
mRecentTasks = recentTasks;
mMainUnfoldController = unfoldControllerProvider.get().orElse(null);
mSideUnfoldController = unfoldControllerProvider.get().orElse(null);
+ taskOrganizer.createRootTask(displayId, WINDOWING_MODE_FULLSCREEN, this /* listener */);
mMainStage = new MainStage(
mContext,
@@ -224,7 +228,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mDisplayImeController = displayImeController;
mDisplayInsetsController = displayInsetsController;
mTransactionPool = transactionPool;
- mRootTDAOrganizer.registerListener(displayId, this);
final DeviceStateManager deviceStateManager =
mContext.getSystemService(DeviceStateManager.class);
deviceStateManager.registerCallback(taskOrganizer.getExecutor(),
@@ -238,9 +241,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@VisibleForTesting
StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
- RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
- MainStage mainStage, SideStage sideStage, DisplayController displayController,
- DisplayImeController displayImeController,
+ ShellTaskOrganizer taskOrganizer, MainStage mainStage, SideStage sideStage,
+ DisplayController displayController, DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController, SplitLayout splitLayout,
Transitions transitions, TransactionPool transactionPool,
SplitscreenEventLogger logger,
@@ -249,7 +251,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mContext = context;
mDisplayId = displayId;
mSyncQueue = syncQueue;
- mRootTDAOrganizer = rootTDAOrganizer;
mTaskOrganizer = taskOrganizer;
mMainStage = mainStage;
mSideStage = sideStage;
@@ -257,7 +258,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mDisplayImeController = displayImeController;
mDisplayInsetsController = displayInsetsController;
mTransactionPool = transactionPool;
- mRootTDAOrganizer.registerListener(displayId, this);
mSplitLayout = splitLayout;
mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
this::onTransitionAnimationComplete, this);
@@ -357,6 +357,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// while task 1 is on the side stage.
mMainStage.activate(wct, false /* reparent */);
updateWindowBounds(mSplitLayout, wct);
+ wct.reorder(mRootTaskInfo.token, true);
// Make sure the launch options will put tasks in the corresponding split roots
addActivityOptions(mainOptions, mMainStage);
@@ -470,15 +471,13 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
setSideStagePosition(sidePosition, wct);
mSplitLayout.setDivideRatio(splitRatio);
- if (mMainStage.isActive()) {
- mMainStage.moveToTop(wct);
- } else {
+ if (!mMainStage.isActive()) {
// Build a request WCT that will launch both apps such that task 0 is on the main stage
// while task 1 is on the side stage.
mMainStage.activate(wct, false /* reparent */);
}
- mSideStage.moveToTop(wct);
updateWindowBounds(mSplitLayout, wct);
+ wct.reorder(mRootTaskInfo.token, true);
// Make sure the launch options will put tasks in the corresponding split roots
addActivityOptions(mainOptions, mMainStage);
@@ -603,14 +602,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
- void setSideStageVisibility(boolean visible) {
- if (mSideStageListener.mVisible == visible) return;
-
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- mSideStage.setVisibility(visible, wct);
- mTaskOrganizer.applyTransaction(wct);
- }
-
void onKeyguardVisibilityChanged(boolean showing) {
if (!mMainStage.isActive()) {
return;
@@ -682,15 +673,18 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
applyExitSplitScreen(childrenToTop, wct, exitReason);
}
- private void exitSplitScreen(StageTaskListener childrenToTop, @ExitReason int exitReason) {
+ private void exitSplitScreen(@Nullable StageTaskListener childrenToTop,
+ @ExitReason int exitReason) {
if (!mMainStage.isActive()) return;
final WindowContainerTransaction wct = new WindowContainerTransaction();
applyExitSplitScreen(childrenToTop, wct, exitReason);
}
- private void applyExitSplitScreen(StageTaskListener childrenToTop,
+ private void applyExitSplitScreen(@Nullable StageTaskListener childrenToTop,
WindowContainerTransaction wct, @ExitReason int exitReason) {
+ if (!mMainStage.isActive()) return;
+
mRecentTasks.ifPresent(recentTasks -> {
// Notify recents if we are exiting in a way that breaks the pair, and disable further
// updates to splits in the recents until we enter split again
@@ -705,8 +699,9 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// we want the tasks to be put to bottom instead of top, otherwise it will end up
// a fullscreen plus a pinned task instead of pinned only at the end of the transition.
final boolean fromEnteringPip = exitReason == EXIT_REASON_CHILD_TASK_ENTER_PIP;
- mSideStage.removeAllTasks(wct, !fromEnteringPip && childrenToTop == mSideStage);
- mMainStage.deactivate(wct, !fromEnteringPip && childrenToTop == mMainStage);
+ mSideStage.removeAllTasks(wct, !fromEnteringPip && mSideStage == childrenToTop);
+ mMainStage.deactivate(wct, !fromEnteringPip && mMainStage == childrenToTop);
+ wct.reorder(mRootTaskInfo.token, false /* onTop */);
mTaskOrganizer.applyTransaction(wct);
mSyncQueue.runInSync(t -> t
.setWindowCrop(mMainStage.mRootLeash, null)
@@ -777,8 +772,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSideStage.addTask(taskInfo, wct);
}
mMainStage.activate(wct, true /* includingTopTask */);
- mSideStage.moveToTop(wct);
updateWindowBounds(mSplitLayout, wct);
+ wct.reorder(mRootTaskInfo.token, true);
}
void finishEnterSplitScreen(SurfaceControl.Transaction t) {
@@ -916,25 +911,97 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
- private void onStageRootTaskAppeared(StageListenerImpl stageListener) {
- if (mMainStageListener.mHasRootTask && mSideStageListener.mHasRootTask) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- // Make the stages adjacent to each other so they occlude what's behind them.
- wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token,
- true /* moveTogether */);
- wct.setLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
- mTaskOrganizer.applyTransaction(wct);
+ @Override
+ @CallSuper
+ public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
+ if (mRootTaskInfo != null || taskInfo.hasParentTask()) {
+ throw new IllegalArgumentException(this + "\n Unknown task appeared: " + taskInfo);
+ }
+
+ mRootTaskInfo = taskInfo;
+ mRootTaskLeash = leash;
+
+ if (mSplitLayout == null) {
+ mSplitLayout = new SplitLayout(TAG + "SplitDivider", mContext,
+ mRootTaskInfo.configuration, this, mParentContainerCallbacks,
+ mDisplayImeController, mTaskOrganizer, false /* applyDismissingParallax */);
+ mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSplitLayout);
+ }
+
+ if (mMainUnfoldController != null && mSideUnfoldController != null) {
+ mMainUnfoldController.init();
+ mSideUnfoldController.init();
}
+
+ onRootTaskAppeared();
}
- private void onStageRootTaskVanished(StageListenerImpl stageListener) {
- if (stageListener == mMainStageListener || stageListener == mSideStageListener) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.clearLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
- // Deactivate the main stage if it no longer has a root task.
- mMainStage.deactivate(wct);
- mTaskOrganizer.applyTransaction(wct);
+ @Override
+ @CallSuper
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ if (mRootTaskInfo == null || mRootTaskInfo.taskId != taskInfo.taskId) {
+ throw new IllegalArgumentException(this + "\n Unknown task info changed: " + taskInfo);
+ }
+
+ mRootTaskInfo = taskInfo;
+ if (mSplitLayout != null
+ && mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)
+ && mMainStage.isActive()) {
+ // TODO(b/204925795): With Shell transition, We are handling split bounds rotation at
+ // onRotateDisplay. But still need to handle unfold case.
+ if (ENABLE_SHELL_TRANSITIONS) {
+ updateUnfoldBounds();
+ return;
+ }
+ mSplitLayout.update(null /* t */);
+ onLayoutSizeChanged(mSplitLayout);
+ }
+ }
+
+ @Override
+ @CallSuper
+ public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+ if (mRootTaskInfo == null) {
+ throw new IllegalArgumentException(this + "\n Unknown task vanished: " + taskInfo);
+ }
+
+ onRootTaskVanished();
+
+ if (mSplitLayout != null) {
+ mSplitLayout.release();
+ mSplitLayout = null;
+ }
+
+ mRootTaskInfo = null;
+ }
+
+
+ @VisibleForTesting
+ void onRootTaskAppeared() {
+ // Wait unit all root tasks appeared.
+ if (mRootTaskInfo == null
+ || !mMainStageListener.mHasRootTask
+ || !mSideStageListener.mHasRootTask) {
+ return;
}
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.reparent(mMainStage.mRootTaskInfo.token, mRootTaskInfo.token, true);
+ wct.reparent(mSideStage.mRootTaskInfo.token, mRootTaskInfo.token, true);
+ // Make the stages adjacent to each other so they occlude what's behind them.
+ wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token,
+ true /* moveTogether */);
+ wct.setLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
+ mTaskOrganizer.applyTransaction(wct);
+ }
+
+ private void onRootTaskVanished() {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (mRootTaskInfo != null) {
+ wct.clearLaunchAdjacentFlagRoot(mRootTaskInfo.token);
+ }
+ applyExitSplitScreen(null /* childrenToTop */, wct, EXIT_REASON_ROOT_TASK_VANISHED);
+ mDisplayInsetsController.removeInsetsChangedListener(mDisplayId, mSplitLayout);
}
private void onStageVisibilityChanged(StageListenerImpl stageListener) {
@@ -981,7 +1048,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mDividerVisible) {
t.show(dividerLeash);
t.setAlpha(dividerLeash, 1);
- t.setLayer(dividerLeash, SPLIT_DIVIDER_LAYER);
+ t.setLayer(dividerLeash, Integer.MAX_VALUE);
t.setPosition(dividerLeash,
mSplitLayout.getRefDividerBounds().left,
mSplitLayout.getRefDividerBounds().top);
@@ -1140,45 +1207,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
@Override
- public void onDisplayAreaAppeared(DisplayAreaInfo displayAreaInfo) {
- mDisplayAreaInfo = displayAreaInfo;
- if (mSplitLayout == null) {
- mSplitLayout = new SplitLayout(TAG + "SplitDivider", mContext,
- mDisplayAreaInfo.configuration, this, mParentContainerCallbacks,
- mDisplayImeController, mTaskOrganizer, false /* applyDismissingParallax */);
- mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSplitLayout);
-
- if (mMainUnfoldController != null && mSideUnfoldController != null) {
- mMainUnfoldController.init();
- mSideUnfoldController.init();
- }
- }
- }
-
- @Override
- public void onDisplayAreaVanished(DisplayAreaInfo displayAreaInfo) {
- throw new IllegalStateException("Well that was unexpected...");
- }
-
- @Override
- public void onDisplayAreaInfoChanged(DisplayAreaInfo displayAreaInfo) {
- mDisplayAreaInfo = displayAreaInfo;
- if (mSplitLayout != null
- && mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration)
- && mMainStage.isActive()) {
- // TODO(b/204925795): With Shell transition, We are handle roation case for apply split
- // bounds at onRotateDisplay. But still need to handle unfold case.
- if (ENABLE_SHELL_TRANSITIONS) {
- updateUnfoldBounds();
- return;
- }
-
- mSplitLayout.update(null /* t */);
- onLayoutSizeChanged(mSplitLayout);
- }
- }
-
- @Override
public void onDisplayAdded(int displayId) {
if (displayId != DEFAULT_DISPLAY) {
return;
@@ -1200,13 +1228,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Only do this when shell transition
if (!ENABLE_SHELL_TRANSITIONS) return;
- final SurfaceControl.Transaction t = mTransactionPool.acquire();
mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
mSplitLayout.rotateTo(toRotation, mDisplayLayout.stableInsets());
updateWindowBounds(mSplitLayout, wct);
updateUnfoldBounds();
- t.apply();
- mTransactionPool.release(t);
}
private void onFoldedStateChanged(boolean folded) {
@@ -1258,7 +1283,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
if (triggerTask == null) {
if (mMainStage.isActive()) {
- if (request.getType() == TRANSIT_CHANGE && request.getDisplayChange() != null) {
+ final TransitionRequestInfo.DisplayChange displayChange =
+ request.getDisplayChange();
+ if (request.getType() == TRANSIT_CHANGE && displayChange != null
+ && displayChange.getStartRotation() != displayChange.getEndRotation()) {
mSplitLayout.setFreezeDividerWindow(true);
}
// Still want to monitor everything while in split-screen, so return non-null.
@@ -1540,8 +1568,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
logExit(dismissTransition.mReason);
// TODO: Have a proper remote for this. Until then, though, reset state and use the
// normal animation stuff (which falls back to the normal launcher remote).
- setDividerVisibility(false, t);
- mSplitLayout.release();
+ mSplitLayout.release(t);
mSplitTransitions.mPendingDismiss = null;
return false;
} else {
@@ -1567,7 +1594,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return true;
}
- void finishRecentAnimation(boolean dismissSplit) {
+ void onRecentTransitionFinished(boolean returnToHome, WindowContainerTransaction wct,
+ SurfaceControl.Transaction finishT) {
// Exclude the case that the split screen has been dismissed already.
if (!mMainStage.isActive()) {
// The latest split dismissing transition might be a no-op transition and thus won't
@@ -1577,13 +1605,14 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return;
}
- if (dismissSplit) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (returnToHome) {
+ // When returning to home from recent apps, the splitting tasks are already hidden, so
+ // append the reset of dismissing operations into the clean-up wct.
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
- mSplitTransitions.startDismissTransition(null /* transition */, wct, this,
- STAGE_TYPE_UNDEFINED, EXIT_REASON_RETURN_HOME);
+ setSplitsVisible(false);
+ logExit(EXIT_REASON_RETURN_HOME);
} else {
- setDividerVisibility(true, null /* t */);
+ setDividerVisibility(true, finishT);
}
}
@@ -1602,7 +1631,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Be default, make it visible. The remote animator can adjust alpha if it plans to animate.
if (show) {
t.setAlpha(leash, 1.f);
- t.setLayer(leash, SPLIT_DIVIDER_LAYER);
+ t.setLayer(leash, Integer.MAX_VALUE);
t.setPosition(leash, bounds.left, bounds.top);
t.show(leash);
}
@@ -1685,7 +1714,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Override
public void onRootTaskAppeared() {
mHasRootTask = true;
- StageCoordinator.this.onStageRootTaskAppeared(this);
+ StageCoordinator.this.onRootTaskAppeared();
}
@Override
@@ -1715,7 +1744,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Override
public void onRootTaskVanished() {
reset();
- StageCoordinator.this.onStageRootTaskVanished(this);
+ StageCoordinator.this.onRootTaskVanished();
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index fb0eebdf0ac9..9fd5d2003873 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -39,7 +39,6 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
-import com.android.internal.R;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SurfaceUtils;
@@ -108,12 +107,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
mSurfaceSession = surfaceSession;
mIconProvider = iconProvider;
mStageTaskUnfoldController = stageTaskUnfoldController;
-
- // No need to create root task if the device is using legacy split screen.
- // TODO(b/199236198): Remove this check after totally deprecated legacy split.
- if (!context.getResources().getBoolean(R.bool.config_useLegacySplit)) {
- taskOrganizer.createRootTask(displayId, WINDOWING_MODE_MULTI_WINDOW, this);
- }
+ taskOrganizer.createRootTask(displayId, WINDOWING_MODE_MULTI_WINDOW, this);
}
int getChildCount() {
@@ -187,7 +181,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
@Override
@CallSuper
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- if (mRootTaskInfo == null && !taskInfo.hasParentTask()) {
+ if (mRootTaskInfo == null) {
mRootLeash = leash;
mRootTaskInfo = taskInfo;
mSplitDecorManager = new SplitDecorManager(
@@ -334,11 +328,6 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
wct.reparent(task.token, mRootTaskInfo.token, true /* onTop*/);
}
- void moveToTop(WindowContainerTransaction wct) {
- final WindowContainerToken rootToken = mRootTaskInfo.token;
- wct.reorder(rootToken, true /* onTop */);
- }
-
void reorderChild(int taskId, boolean onTop, WindowContainerTransaction wct) {
if (!containsTask(taskId)) {
return;
@@ -354,10 +343,6 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
}
}
- void setVisibility(boolean visible, WindowContainerTransaction wct) {
- wct.reorder(mRootTaskInfo.token, visible /* onTop */);
- }
-
void onSplitScreenListenerRegistered(SplitScreen.SplitScreenListener listener,
@StageType int stage) {
for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java
index a17942ff7cff..6ef20e37d5bc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java
@@ -23,7 +23,6 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.transitTypeToString;
-import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_DOES_NOT_SUPPORT_MULTIWINDOW;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED;
@@ -722,7 +721,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mDividerVisible) {
t.show(dividerLeash)
- .setLayer(dividerLeash, SPLIT_DIVIDER_LAYER)
+ .setLayer(dividerLeash, Integer.MAX_VALUE)
.setPosition(dividerLeash,
mSplitLayout.getDividerBounds().left,
mSplitLayout.getDividerBounds().top);
@@ -738,7 +737,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
if (mDividerVisible) {
- t.show(outlineLeash).setLayer(outlineLeash, SPLIT_DIVIDER_LAYER);
+ t.show(outlineLeash).setLayer(outlineLeash, Integer.MAX_VALUE);
} else {
t.hide(outlineLeash);
}
@@ -1190,7 +1189,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Be default, make it visible. The remote animator can adjust alpha if it plans to animate.
if (show) {
t.setAlpha(leash, 1.f);
- t.setLayer(leash, SPLIT_DIVIDER_LAYER);
+ t.setLayer(leash, Integer.MAX_VALUE);
t.setPosition(leash, bounds.left, bounds.top);
t.show(leash);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 04d6ef7f9505..11f23e3e941b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -633,7 +633,7 @@ public class StartingSurfaceDrawer {
Slog.e(TAG, "Found empty splash screen, remove!");
removeWindowInner(record.mDecorView, false);
}
- mStartingWindowRecords.remove(taskId);
+
}
if (record.mTaskSnapshotWindow != null) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
@@ -641,10 +641,10 @@ public class StartingSurfaceDrawer {
if (immediately) {
record.mTaskSnapshotWindow.removeImmediately();
} else {
- record.mTaskSnapshotWindow.scheduleRemove(() ->
- mStartingWindowRecords.remove(taskId), removalInfo.deferRemoveForIme);
+ record.mTaskSnapshotWindow.scheduleRemove(removalInfo.deferRemoveForIme);
}
}
+ mStartingWindowRecords.remove(taskId);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 2debcf296ea8..fd6e59ee6a81 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -91,6 +91,8 @@ import com.android.internal.view.BaseIWindow;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import java.lang.ref.WeakReference;
+
/**
* This class represents a starting window that shows a snapshot.
*
@@ -149,7 +151,7 @@ public class TaskSnapshotWindow {
private final SurfaceControl.Transaction mTransaction;
private final Matrix mSnapshotMatrix = new Matrix();
private final float[] mTmpFloat9 = new float[9];
- private Runnable mScheduledRunnable;
+ private final Runnable mScheduledRunnable = this::removeImmediately;
private final boolean mHasImeSurface;
static TaskSnapshotWindow create(StartingWindowInfo info, IBinder appToken,
@@ -306,21 +308,13 @@ public class TaskSnapshotWindow {
mSystemBarBackgroundPainter.drawNavigationBarBackground(c);
}
- void scheduleRemove(Runnable onRemove, boolean deferRemoveForIme) {
+ void scheduleRemove(boolean deferRemoveForIme) {
// Show the latest content as soon as possible for unlocking to home.
if (mActivityType == ACTIVITY_TYPE_HOME) {
removeImmediately();
- onRemove.run();
return;
}
- if (mScheduledRunnable != null) {
- mSplashScreenExecutor.removeCallbacks(mScheduledRunnable);
- mScheduledRunnable = null;
- }
- mScheduledRunnable = () -> {
- TaskSnapshotWindow.this.removeImmediately();
- onRemove.run();
- };
+ mSplashScreenExecutor.removeCallbacks(mScheduledRunnable);
final long delayRemovalTime = mHasImeSurface && deferRemoveForIme
? MAX_DELAY_REMOVAL_TIME_IME_VISIBLE
: DELAY_REMOVAL_TIME_GENERAL;
@@ -524,35 +518,37 @@ public class TaskSnapshotWindow {
}
}
- @BinderThread
static class Window extends BaseIWindow {
- private TaskSnapshotWindow mOuter;
+ private WeakReference<TaskSnapshotWindow> mOuter;
public void setOuter(TaskSnapshotWindow outer) {
- mOuter = outer;
+ mOuter = new WeakReference<>(outer);
}
+ @BinderThread
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState,
boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int seqId,
int resizeMode) {
- if (mOuter != null) {
- mOuter.mSplashScreenExecutor.execute(() -> {
- if (mergedConfiguration != null
- && mOuter.mOrientationOnCreation
- != mergedConfiguration.getMergedConfiguration().orientation) {
- // The orientation of the screen is changing. We better remove the snapshot
- // ASAP as we are going to wait on the new window in any case to unfreeze
- // the screen, and the starting window is not needed anymore.
- mOuter.clearWindowSynced();
- } else if (reportDraw) {
- if (mOuter.mHasDrawn) {
- mOuter.reportDrawn();
- }
- }
- });
+ final TaskSnapshotWindow snapshot = mOuter.get();
+ if (snapshot == null) {
+ return;
}
+ snapshot.mSplashScreenExecutor.execute(() -> {
+ if (mergedConfiguration != null
+ && snapshot.mOrientationOnCreation
+ != mergedConfiguration.getMergedConfiguration().orientation) {
+ // The orientation of the screen is changing. We better remove the snapshot
+ // ASAP as we are going to wait on the new window in any case to unfreeze
+ // the screen, and the starting window is not needed anymore.
+ snapshot.clearWindowSynced();
+ } else if (reportDraw) {
+ if (snapshot.mHasDrawn) {
+ snapshot.reportDrawn();
+ }
+ }
+ });
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index b0e44a15b0da..542ddeea769c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -369,12 +369,20 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
}
if (change.getMode() == TRANSIT_CHANGE) {
- // If task is child task, only set position in parent.
+ // If task is child task, only set position in parent and update crop when needed.
if (isTask && change.getParent() != null
&& info.getChange(change.getParent()).getTaskInfo() != null) {
final Point positionInParent = change.getTaskInfo().positionInParent;
startTransaction.setPosition(change.getLeash(),
positionInParent.x, positionInParent.y);
+
+ if (!change.getEndAbsBounds().equals(
+ info.getChange(change.getParent()).getEndAbsBounds())) {
+ startTransaction.setWindowCrop(change.getLeash(),
+ change.getEndAbsBounds().width(),
+ change.getEndAbsBounds().height());
+ }
+
continue;
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
index f6abc75037ed..b137e92881a5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
@@ -28,9 +28,6 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import org.junit.Assume
-import org.junit.Before
import org.junit.runner.RunWith
import org.junit.Test
import org.junit.runners.Parameterized
@@ -52,11 +49,6 @@ open class DismissBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScree
private val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
private val displaySize = DisplayMetrics()
- @Before
- open fun before() {
- Assume.assumeFalse(isShellTransitionsEnabled)
- }
-
override val transition: FlickerBuilder.() -> Unit
get() = buildTransition {
setup {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreenShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreenShellTransit.kt
deleted file mode 100644
index dd744b3c45ab..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreenShellTransit.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2022 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.bubble
-
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.annotation.Group4
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import org.junit.Assume
-import org.junit.Before
-
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@Group4
-@FlakyTest(bugId = 217777115)
-class DismissBubbleScreenShellTransit(
- testSpec: FlickerTestParameter
-) : DismissBubbleScreen(testSpec) {
- @Before
- override fun before() {
- Assume.assumeTrue(isShellTransitionsEnabled)
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
index 2ec743c10413..f288b0a24d9d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
@@ -24,9 +24,6 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import org.junit.Assume
-import org.junit.Before
import org.junit.runner.RunWith
import org.junit.Test
import org.junit.runners.Parameterized
@@ -47,11 +44,6 @@ import org.junit.runners.Parameterized
@Group4
open class ExpandBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
- @Before
- open fun before() {
- Assume.assumeFalse(isShellTransitionsEnabled)
- }
-
override val transition: FlickerBuilder.() -> Unit
get() = buildTransition {
setup {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreenShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreenShellTransit.kt
deleted file mode 100644
index d92ec7781005..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreenShellTransit.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2022 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.bubble
-
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.annotation.Group4
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import org.junit.Assume
-import org.junit.Before
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@Group4
-@FlakyTest(bugId = 217777115)
-class ExpandBubbleScreenShellTransit(
- testSpec: FlickerTestParameter
-) : ExpandBubbleScreen(testSpec) {
- @Before
- override fun before() {
- Assume.assumeTrue(isShellTransitionsEnabled)
- }
-} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
index c43230e77683..0bb4d398bff4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
@@ -17,15 +17,11 @@
package com.android.wm.shell.flicker.bubble
import android.platform.test.annotations.Presubmit
-import androidx.test.filters.FlakyTest
import android.platform.test.annotations.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import org.junit.Assume
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -45,11 +41,6 @@ import org.junit.runners.Parameterized
@Group4
open class LaunchBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
- @Before
- open fun before() {
- Assume.assumeFalse(isShellTransitionsEnabled)
- }
-
override val transition: FlickerBuilder.() -> Unit
get() = buildTransition {
transitions {
@@ -61,16 +52,6 @@ open class LaunchBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen
@Presubmit
@Test
open fun testAppIsAlwaysVisible() {
- Assume.assumeFalse(isShellTransitionsEnabled)
- testSpec.assertLayers {
- this.isVisible(testApp.component)
- }
- }
-
- @FlakyTest(bugId = 218642026)
- @Test
- open fun testAppIsAlwaysVisible_ShellTransit() {
- Assume.assumeTrue(isShellTransitionsEnabled)
testSpec.assertLayers {
this.isVisible(testApp.component)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreenShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreenShellTransit.kt
deleted file mode 100644
index 9350868a99f4..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreenShellTransit.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2022 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.bubble
-
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.annotation.Group4
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import org.junit.Assume
-import org.junit.Before
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@Group4
-@FlakyTest(bugId = 217777115)
-class LaunchBubbleScreenShellTransit(
- testSpec: FlickerTestParameter
-) : LaunchBubbleScreen(testSpec) {
- @Before
- override fun before() {
- Assume.assumeTrue(isShellTransitionsEnabled)
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
index e2d08346efb6..a3ed79bf0409 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
@@ -74,7 +74,7 @@ class ExitPipViaExpandButtonClickTest(
// This will bring PipApp to fullscreen
pipApp.expandPipWindowToApp(wmHelper)
// Wait until the other app is no longer visible
- wmHelper.waitForSurfaceAppeared(testApp.component)
+ wmHelper.waitForWindowSurfaceDisappeared(testApp.component)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
index 87e927fd50ea..8729bb6776f0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
@@ -24,10 +24,7 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.traces.region.RegionSubject
-import org.junit.Assume
-import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -61,11 +58,6 @@ import org.junit.runners.Parameterized
open class MovePipDownShelfHeightChangeTest(
testSpec: FlickerTestParameter
) : MovePipShelfHeightTransition(testSpec) {
- @Before
- open fun before() {
- Assume.assumeFalse(isShellTransitionsEnabled)
- }
-
/**
* Defines the transition used to run the test
*/
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest_ShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest_ShellTransit.kt
deleted file mode 100644
index 0ff260b94dc8..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest_ShellTransit.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-import androidx.test.filters.FlakyTest
-import android.platform.test.annotations.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.annotation.Group3
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import org.junit.Assume
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test Pip movement with Launcher shelf height change (decrease).
- *
- * To run this test: `atest WMShellFlickerTests:MovePipDownShelfHeightChangeTest`
- *
- * Actions:
- * Launch [pipApp] in pip mode
- * Launch [testApp]
- * Press home
- * Check if pip window moves down (visually)
- *
- * Notes:
- * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
- * are inherited [PipTransition]
- * 2. Part of the test setup occurs automatically via
- * [com.android.server.wm.flicker.TransitionRunnerWithRules],
- * including configuring navigation mode, initial orientation and ensuring no
- * apps are running before setup
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group3
-@FlakyTest(bugId = 219693385)
-class MovePipDownShelfHeightChangeTest_ShellTransit(
- testSpec: FlickerTestParameter
-) : MovePipDownShelfHeightChangeTest(testSpec) {
- @Before
- override fun before() {
- Assume.assumeTrue(isShellTransitionsEnabled)
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index c8ced1c9df12..6af01e24f58c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -64,7 +64,6 @@ import org.junit.runners.Parameterized
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group4
-@FlakyTest(bugId = 218604389)
open class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
private val fixedApp = FixedAppHelper(instrumentation)
private val screenBoundsStart = WindowUtils.getDisplayBounds(testSpec.startRotation)
@@ -138,7 +137,7 @@ open class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testS
*/
@Presubmit
@Test
- fun pipLayerRotates_StartingBounds() {
+ open fun pipLayerRotates_StartingBounds() {
testSpec.assertLayersStart {
visibleRegion(pipApp.component).coversAtMost(screenBoundsStart)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTestShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTestShellTransit.kt
index a017f56af5bd..2252a949ba00 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTestShellTransit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTestShellTransit.kt
@@ -34,10 +34,12 @@ import org.junit.runners.Parameterized
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group4
-@FlakyTest(bugId = 217777115)
class PipRotationTestShellTransit(testSpec: FlickerTestParameter) : PipRotationTest(testSpec) {
@Before
override fun before() {
Assume.assumeTrue(isShellTransitionsEnabled)
}
+
+ @FlakyTest(bugId = 227214914)
+ override fun pipLayerRotates_StartingBounds() = super.pipLayerRotates_StartingBounds()
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index f7384e742a04..81403d08ff20 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -28,13 +28,10 @@ import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
import com.android.wm.shell.flicker.testapp.Components
import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION
-import org.junit.Assume
-import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -57,11 +54,6 @@ open class SetRequestedOrientationWhilePinnedTest(
private val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0)
private val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90)
- @Before
- open fun before() {
- Assume.assumeFalse(isShellTransitionsEnabled)
- }
-
override val transition: FlickerBuilder.() -> Unit
get() = {
setup {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt
deleted file mode 100644
index 8d764a8d0e69..000000000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2022 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 androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.annotation.Group4
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import org.junit.Assume
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test exiting Pip with orientation changes.
- * To run this test: `atest WMShellFlickerTests:SetRequestedOrientationWhilePinnedTestShellTransit`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group4
-@FlakyTest(bugId = 217777115)
-class SetRequestedOrientationWhilePinnedTestShellTransit(
- testSpec: FlickerTestParameter
-) : SetRequestedOrientationWhilePinnedTest(testSpec) {
- @Before
- override fun before() {
- Assume.assumeTrue(isShellTransitionsEnabled)
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 05230a9417bb..7c1fae3a849b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -118,6 +118,7 @@ public class BackAnimationControllerTest {
BackNavigationInfo.TYPE_CROSS_ACTIVITY);
mController.onMotionEvent(
MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0),
+ MotionEvent.ACTION_DOWN,
BackEvent.EDGE_LEFT);
verify(mTransaction).setBuffer(screenshotSurface, hardwareBuffer);
verify(mTransaction).setVisibility(screenshotSurface, true);
@@ -133,9 +134,11 @@ public class BackAnimationControllerTest {
BackNavigationInfo.TYPE_CROSS_ACTIVITY);
mController.onMotionEvent(
MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0),
+ MotionEvent.ACTION_DOWN,
BackEvent.EDGE_LEFT);
mController.onMotionEvent(
MotionEvent.obtain(10, 0, MotionEvent.ACTION_MOVE, 100, 100, 0),
+ MotionEvent.ACTION_MOVE,
BackEvent.EDGE_LEFT);
verify(mTransaction).setPosition(animationTarget.leash, 100, 100);
verify(mTransaction, atLeastOnce()).apply();
@@ -151,12 +154,14 @@ public class BackAnimationControllerTest {
// Check that back start is dispatched.
mController.onMotionEvent(
MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0),
+ MotionEvent.ACTION_DOWN,
BackEvent.EDGE_LEFT);
verify(mIOnBackInvokedCallback).onBackStarted();
// Check that back progress is dispatched.
mController.onMotionEvent(
MotionEvent.obtain(10, 0, MotionEvent.ACTION_MOVE, 100, 100, 0),
+ MotionEvent.ACTION_MOVE,
BackEvent.EDGE_LEFT);
ArgumentCaptor<BackEvent> backEventCaptor = ArgumentCaptor.forClass(BackEvent.class);
verify(mIOnBackInvokedCallback).onBackProgressed(backEventCaptor.capture());
@@ -166,6 +171,7 @@ public class BackAnimationControllerTest {
mController.setTriggerBack(true); // Fake trigger back
mController.onMotionEvent(
MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0),
+ MotionEvent.ACTION_UP,
BackEvent.EDGE_LEFT);
verify(mIOnBackInvokedCallback).onBackInvoked();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index daec336fc71e..8b4e1f8bfdb7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -16,7 +16,6 @@
package com.android.wm.shell.common.split;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static com.google.common.truth.Truth.assertThat;
@@ -85,10 +84,6 @@ public class SplitLayoutTests extends ShellTestCase {
// Verify it returns true if new config won't affect split layout.
assertThat(mSplitLayout.updateConfiguration(config)).isFalse();
- // Verify updateConfiguration returns true if the orientation changed.
- config.orientation = ORIENTATION_LANDSCAPE;
- assertThat(mSplitLayout.updateConfiguration(config)).isTrue();
-
// Verify updateConfiguration returns true if it rotated.
config.windowConfiguration.setRotation(1);
assertThat(mSplitLayout.updateConfiguration(config)).isTrue();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index 85527c81ad9e..49f36a4be35f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -16,22 +16,18 @@
package com.android.wm.shell.splitscreen;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
-
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Rect;
import android.view.SurfaceControl;
-import android.window.DisplayAreaInfo;
-import android.window.IWindowContainerToken;
-import android.window.WindowContainerToken;
+import android.view.SurfaceSession;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
-import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
@@ -68,26 +64,24 @@ public class SplitTestUtils {
}
static class TestStageCoordinator extends StageCoordinator {
- final DisplayAreaInfo mDisplayAreaInfo;
+ final ActivityManager.RunningTaskInfo mRootTask;
+ final SurfaceControl mRootLeash;
TestStageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
- RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
- MainStage mainStage, SideStage sideStage, DisplayController displayController,
- DisplayImeController imeController, DisplayInsetsController insetsController,
- SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool,
- SplitscreenEventLogger logger,
- Optional<RecentTasksController> recentTasks,
+ ShellTaskOrganizer taskOrganizer, MainStage mainStage, SideStage sideStage,
+ DisplayController displayController, DisplayImeController imeController,
+ DisplayInsetsController insetsController, SplitLayout splitLayout,
+ Transitions transitions, TransactionPool transactionPool,
+ SplitscreenEventLogger logger, Optional<RecentTasksController> recentTasks,
Provider<Optional<StageTaskUnfoldController>> unfoldController) {
- super(context, displayId, syncQueue, rootTDAOrganizer, taskOrganizer, mainStage,
+ super(context, displayId, syncQueue, taskOrganizer, mainStage,
sideStage, displayController, imeController, insetsController, splitLayout,
transitions, transactionPool, logger, recentTasks, unfoldController);
- // Prepare default TaskDisplayArea for testing.
- mDisplayAreaInfo = new DisplayAreaInfo(
- new WindowContainerToken(new IWindowContainerToken.Default()),
- DEFAULT_DISPLAY,
- FEATURE_DEFAULT_TASK_CONTAINER);
- this.onDisplayAreaAppeared(mDisplayAreaInfo);
+ // Prepare root task for testing.
+ mRootTask = new TestRunningTaskInfoBuilder().build();
+ mRootLeash = new SurfaceControl.Builder(new SurfaceSession()).setName("test").build();
+ onTaskAppeared(mRootTask, mRootLeash);
}
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index 19d2a7ef6f45..f847e6eb5e96 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -124,9 +124,9 @@ public class SplitTransitionTests extends ShellTestCase {
mIconProvider, null);
mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
- mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
- mDisplayController, mDisplayImeController, mDisplayInsetsController, mSplitLayout,
- mTransitions, mTransactionPool, mLogger, Optional.empty(), Optional::empty);
+ mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController,
+ mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions,
+ mTransactionPool, mLogger, Optional.empty(), Optional::empty);
mSplitScreenTransitions = mStageCoordinator.getSplitTransitions();
doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class))
.when(mTransitions).startTransition(anyInt(), any(), any());
@@ -424,19 +424,14 @@ public class SplitTransitionTests extends ShellTestCase {
}
private boolean containsSplitEnter(@NonNull WindowContainerTransaction wct) {
- boolean movedMainToFront = false;
- boolean movedSideToFront = false;
for (int i = 0; i < wct.getHierarchyOps().size(); ++i) {
WindowContainerTransaction.HierarchyOp op = wct.getHierarchyOps().get(i);
- if (op.getType() == HIERARCHY_OP_TYPE_REORDER) {
- if (op.getContainer() == mMainStage.mRootTaskInfo.token.asBinder()) {
- movedMainToFront = true;
- } else if (op.getContainer() == mSideStage.mRootTaskInfo.token.asBinder()) {
- movedSideToFront = true;
- }
+ if (op.getType() == HIERARCHY_OP_TYPE_REORDER
+ && op.getContainer() == mStageCoordinator.mRootTaskInfo.token.asBinder()) {
+ return true;
}
}
- return movedMainToFront && movedSideToFront;
+ return false;
}
private boolean containsSplitExit(@NonNull WindowContainerTransaction wct) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index a6ee8ff147db..061136c65daf 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -34,21 +34,20 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.view.SurfaceControl;
-import android.window.DisplayAreaInfo;
+import android.view.SurfaceSession;
import android.window.WindowContainerTransaction;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
@@ -81,8 +80,6 @@ public class StageCoordinatorTests extends ShellTestCase {
@Mock
private SyncTransactionQueue mSyncQueue;
@Mock
- private RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
- @Mock
private MainStage mMainStage;
@Mock
private SideStage mSideStage;
@@ -108,17 +105,27 @@ public class StageCoordinatorTests extends ShellTestCase {
private final Rect mBounds1 = new Rect(10, 20, 30, 40);
private final Rect mBounds2 = new Rect(5, 10, 15, 20);
+ private SurfaceSession mSurfaceSession = new SurfaceSession();
+ private SurfaceControl mRootLeash;
+ private ActivityManager.RunningTaskInfo mRootTask;
private StageCoordinator mStageCoordinator;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mStageCoordinator = spy(createStageCoordinator(mSplitLayout));
+ mStageCoordinator = spy(new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
+ mTaskOrganizer, mMainStage, mSideStage, mDisplayController, mDisplayImeController,
+ mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool, mLogger,
+ Optional.empty(), new UnfoldControllerProvider()));
doNothing().when(mStageCoordinator).updateActivityOptions(any(), anyInt());
when(mSplitLayout.getBounds1()).thenReturn(mBounds1);
when(mSplitLayout.getBounds2()).thenReturn(mBounds2);
when(mSplitLayout.isLandscape()).thenReturn(false);
+
+ mRootTask = new TestRunningTaskInfoBuilder().build();
+ mRootLeash = new SurfaceControl.Builder(mSurfaceSession).setName("test").build();
+ mStageCoordinator.onTaskAppeared(mRootTask, mRootLeash);
}
@Test
@@ -158,14 +165,17 @@ public class StageCoordinatorTests extends ShellTestCase {
}
@Test
- public void testDisplayAreaAppeared_initializesUnfoldControllers() {
- // Create a stage coordinator with null split layout to test layout init flow.
- mStageCoordinator = createStageCoordinator(null /* splitLayout */);
-
- mStageCoordinator.onDisplayAreaAppeared(mock(DisplayAreaInfo.class));
-
+ public void testRootTaskAppeared_initializesUnfoldControllers() {
verify(mMainUnfoldController).init();
verify(mSideUnfoldController).init();
+ verify(mStageCoordinator).onRootTaskAppeared();
+ }
+
+ @Test
+ public void testRootTaskInfoChanged_updatesSplitLayout() {
+ mStageCoordinator.onTaskInfoChanged(mRootTask);
+
+ verify(mSplitLayout).updateConfiguration(any(Configuration.class));
}
@Test
@@ -302,14 +312,6 @@ public class StageCoordinatorTests extends ShellTestCase {
verify(mSplitLayout).applySurfaceChanges(any(), any(), any(), any(), any());
}
- private StageCoordinator createStageCoordinator(SplitLayout splitLayout) {
- return new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
- mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
- mDisplayController, mDisplayImeController, mDisplayInsetsController, splitLayout,
- mTransitions, mTransactionPool, mLogger, Optional.empty(),
- new UnfoldControllerProvider());
- }
-
private class UnfoldControllerProvider implements
Provider<Optional<StageTaskUnfoldController>> {
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 0e4a1f945b85..99fd463b0660 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -74,7 +74,15 @@ bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, con
if (backBuffer.get() == nullptr) {
return false;
}
- LightingInfo::updateLighting(lightGeometry, lightInfo);
+
+ // update the coordinates of the global light position based on surface rotation
+ SkPoint lightCenter = mVkSurface->getCurrentPreTransform().mapXY(lightGeometry.center.x,
+ lightGeometry.center.y);
+ LightGeometry localGeometry = lightGeometry;
+ localGeometry.center.x = lightCenter.fX;
+ localGeometry.center.y = lightCenter.fY;
+
+ LightingInfo::updateLighting(localGeometry, lightInfo);
renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer,
mVkSurface->getCurrentPreTransform());
diff --git a/location/java/android/location/OWNERS b/location/java/android/location/OWNERS
index 60321448a58a..b5c970ae31b9 100644
--- a/location/java/android/location/OWNERS
+++ b/location/java/android/location/OWNERS
@@ -1,6 +1,9 @@
# Bug component: 880425
+dnchrist@google.com
+etn@google.com
+lifu@google.com
+mstogaitis@google.com
sooniln@google.com
wyattriley@google.com
yuhany@google.com
-weiwa@google.com
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 00c4a9782f33..a2826cb58ccf 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -85,12 +85,13 @@ bool checkLoop(int32_t *loop)
} // namespace
SoundPool::SoundPool(
- int32_t maxStreams, const audio_attributes_t* attributes, const std::string& opPackageName)
+ int32_t maxStreams, const audio_attributes_t& attributes,
+ const std::string& opPackageName)
: mStreamManager(maxStreams, kStreamManagerThreads, attributes, opPackageName)
{
ALOGV("%s(maxStreams=%d, attr={ content_type=%d, usage=%d, flags=0x%x, tags=%s })",
__func__, maxStreams,
- attributes->content_type, attributes->usage, attributes->flags, attributes->tags);
+ attributes.content_type, attributes.usage, attributes.flags, attributes.tags);
}
SoundPool::~SoundPool()
diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h
index ffb1c997393a..6bb971b07e43 100644
--- a/media/jni/soundpool/SoundPool.h
+++ b/media/jni/soundpool/SoundPool.h
@@ -31,7 +31,7 @@ namespace android {
*/
class SoundPool {
public:
- SoundPool(int32_t maxStreams, const audio_attributes_t* attributes,
+ SoundPool(int32_t maxStreams, const audio_attributes_t& attributes,
const std::string& opPackageName = {});
~SoundPool();
diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp
index 7f987e31d1d8..487a696d8765 100644
--- a/media/jni/soundpool/StreamManager.cpp
+++ b/media/jni/soundpool/StreamManager.cpp
@@ -106,10 +106,10 @@ int32_t StreamMap::getNextIdForStream(Stream* stream) const {
#pragma clang diagnostic ignored "-Wthread-safety-analysis"
StreamManager::StreamManager(
- int32_t streams, size_t threads, const audio_attributes_t* attributes,
+ int32_t streams, size_t threads, const audio_attributes_t& attributes,
std::string opPackageName)
: StreamMap(streams)
- , mAttributes(*attributes)
+ , mAttributes(attributes)
, mOpPackageName(std::move(opPackageName))
, mLockStreamManagerStop(streams == 1 || kForceLockStreamManagerStop)
{
diff --git a/media/jni/soundpool/StreamManager.h b/media/jni/soundpool/StreamManager.h
index 85b468cd2cbc..ec65b0c49dc4 100644
--- a/media/jni/soundpool/StreamManager.h
+++ b/media/jni/soundpool/StreamManager.h
@@ -387,7 +387,7 @@ class StreamManager : public StreamMap {
public:
// Note: the SoundPool pointer is only used for stream initialization.
// It is not stored in StreamManager.
- StreamManager(int32_t streams, size_t threads, const audio_attributes_t* attributes,
+ StreamManager(int32_t streams, size_t threads, const audio_attributes_t& attributes,
std::string opPackageName);
~StreamManager();
diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
index 14b0c11c986a..5264772be7c3 100644
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -520,7 +520,7 @@ android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz,
(audio_flags_mask_t) env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
ScopedUtfChars opPackageNameStr(env, opPackageName);
auto soundPool = std::make_shared<SoundPool>(
- maxChannels, &audioAttributes, opPackageNameStr.c_str());
+ maxChannels, audioAttributes, opPackageNameStr.c_str());
soundPool->setCallback(android_media_callback, nullptr /* user */);
// register with SoundPoolManager.
diff --git a/media/jni/soundpool/tests/soundpool_stress.cpp b/media/jni/soundpool/tests/soundpool_stress.cpp
index 7d9b6a21b5c4..0116a99b2ba9 100644
--- a/media/jni/soundpool/tests/soundpool_stress.cpp
+++ b/media/jni/soundpool/tests/soundpool_stress.cpp
@@ -274,7 +274,7 @@ int main(int argc, char *argv[])
.content_type = AUDIO_CONTENT_TYPE_MUSIC,
.usage = AUDIO_USAGE_MEDIA,
};
- auto soundPool = std::make_unique<SoundPool>(maxStreams, &aa);
+ auto soundPool = std::make_unique<SoundPool>(maxStreams, aa);
gCallbackManager.setSoundPool(soundPool.get());
soundPool->setCallback(StaticCallbackManager, &gCallbackManager);
diff --git a/native/android/activity_manager.cpp b/native/android/activity_manager.cpp
index 82f4569b871e..155a355241c8 100644
--- a/native/android/activity_manager.cpp
+++ b/native/android/activity_manager.cpp
@@ -45,6 +45,7 @@ struct UidObserver : public BnUidObserver, public virtual IBinder::DeathRecipien
void onUidIdle(uid_t uid, bool disabled) override;
void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
int32_t capability) override;
+ void onUidProcAdjChanged(uid_t uid) override;
// IBinder::DeathRecipient implementation
void binderDied(const wp<IBinder>& who) override;
@@ -120,6 +121,8 @@ void UidObserver::onUidActive(uid_t uid __unused) {}
void UidObserver::onUidIdle(uid_t uid __unused, bool disabled __unused) {}
+void UidObserver::onUidProcAdjChanged(uid_t uid __unused) {}
+
void UidObserver::onUidStateChanged(uid_t uid, int32_t procState,
int64_t procStateSeq __unused,
int32_t capability __unused) {
diff --git a/native/android/libandroid_net.map.txt b/native/android/libandroid_net.map.txt
index 32fd734d61a0..e9acdae4576a 100644
--- a/native/android/libandroid_net.map.txt
+++ b/native/android/libandroid_net.map.txt
@@ -5,20 +5,20 @@
# which might be a few years old.
LIBANDROID_NET {
global:
- # These functions have been part of the NDK since API 24.
+ # These functions have been part of the LL-NDK since API 24.
android_getaddrinfofornetwork; # llndk
android_setsocknetwork; # llndk
android_setprocnetwork; # llndk
- # These functions have been part of the NDK since API 29.
+ # These functions have been part of the LL-NDK since API 29.
android_res_cancel; # llndk
android_res_nquery; # llndk
android_res_nresult; # llndk
android_res_nsend; # llndk
- # These functions have been part of the NDK since API 31.
+ # These functions have been part of the LL-NDK since API 31.
android_getprocnetwork; # llndk
android_setprocdns; # llndk
android_getprocdns; # llndk
- # These functions have been part of the NDK since API 33.
+ # These functions have been part of the LL-NDK since API 33.
android_tag_socket_with_uid; # llndk
android_tag_socket; # llndk
android_untag_socket; # llndk
diff --git a/native/android/net.c b/native/android/net.c
index d7c22e1a5741..74db1845080b 100644
--- a/native/android/net.c
+++ b/native/android/net.c
@@ -162,11 +162,11 @@ void android_res_cancel(int nsend_fd) {
resNetworkCancel(nsend_fd);
}
-int android_tag_socket_with_uid(int sockfd, int tag, uid_t uid) {
+int android_tag_socket_with_uid(int sockfd, uint32_t tag, uid_t uid) {
return tagSocket(sockfd, tag, uid);
}
-int android_tag_socket(int sockfd, int tag) {
+int android_tag_socket(int sockfd, uint32_t tag) {
return tagSocket(sockfd, tag, -1);
}
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index 9a0730243c46..b099d0cb4ef9 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"আপোনাৰ ফ’নৰ এপ্‌ ষ্ট্ৰীম কৰক"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ ফ’নৰ পৰা এই তথ্যখিনি এক্সেছ কৰাৰ অনুমতি দিয়ক"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ক্ৰছ-ডিভাইচ সেৱাসমূহ"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ৰ হৈ আপোনাৰ ফ’নৰ ফট’ মিডিয়া আৰু জাননী এক্সেছ কৰাৰ বাবে অনুৰোধ জনাইছে"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ ফ’নৰ পৰা এই তথ্যখিনি এক্সেছ কৰাৰ অনুমতি দিয়ক"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"ফট’ আৰু মিডিয়া"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play সেৱা"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ৰ হৈ আপোনাৰ ডিভাইচসমূহৰ মাজত এপ্‌ ষ্ট্ৰীম কৰাৰ বাবে অনুৰোধ জনাইছে"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইচ"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিয়ক"</string>
<string name="consent_no" msgid="2640796915611404382">"অনুমতি নিদিব"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"উভতি যাওক"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"আপোনাৰ ঘড়ীলৈ এপৰ অনুমতিসমূহ স্থানান্তৰ কৰক"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"আপোনাৰ ঘড়ীটো ছেটআপ কৰাটো অধিক সহজ কৰি তুলিবলৈ, এয়া কৰাৰ সময়ত আপোনাৰ ঘড়ীটোত ইনষ্টল কৰি থোৱা এপ্‌সমূহে আপোনাৰ ফ’নৰ দৰে একেই অনুমতিসমূহ ব্যৱহাৰ কৰিব।\n\n এই অনুমতিসমূহত আপোনাৰ ঘড়ীৰ মাইক্ৰ’ফ’ন আৰু অৱস্থানৰ এক্সেছ অন্তৰ্ভুক্ত হ’ব পাৰে।"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index 4592e884c328..1166ca1f4678 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"Telefonunuzun tətbiqlərini yayımlayın"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə telefonunuzdan bu məlumata giriş icazəsi verin"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlararası xidmətlər"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> adından telefonunuzun fotoları, mediası və bildirişlərinə giriş üçün icazə istəyir"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə telefonunuzdan bu məlumata giriş icazəsi verin"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Foto və media"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play xidmətləri"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> adından cihazlarınız arasında tətbiqləri yayımlamaq üçün icazə istəyir"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"İcazə verin"</string>
<string name="consent_no" msgid="2640796915611404382">"İcazə verməyin"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Geriyə"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Tətbiq icazələrini saatınıza köçürün"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Saatınızı ayarlamağı asanlaşdırmaq üçün ayarlama zamanı saatınızda quraşdırılmış tətbiqlər telefonunuzla eyni icazələrdən istifadə edəcək.\n\n Bu icazələrə saatınızın mikrofonuna və məkanına giriş daxil ola bilər."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index 3e9a5a328587..9123e05d912f 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"Strimujte aplikacije na telefonu"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama sa telefona"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na više uređaja"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za pristup slikama, medijskom sadržaju i obaveštenjima sa telefona"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama sa telefona"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Slike i mediji"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play usluge"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za strimovanje aplikacija između uređaja"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string>
<string name="consent_no" msgid="2640796915611404382">"Ne dozvoli"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Nazad"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prenesite dozvole za aplikacije na sat"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Da bismo pojednostavili podešavanje sata, aplikacije instalirane na satu tokom podešavanja će koristiti iste dozvole kao telefon.\n\n Te dozvole mogu da obuhvataju pristup mikrofonu i lokaciji sata."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index eff7709e9c92..527a3f207d19 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"Prenosite aplikacije s telefona"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama s telefona"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluga na više uređaja"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> da pristupi fotografijama, medijskim sadržajima i obavijestima na telefonu"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa ovim informacijama s vašeg telefona"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Fotografije i mediji"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play usluge"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za streamanje aplikacija između vaših uređaja"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string>
<string name="consent_no" msgid="2640796915611404382">"Nemoj dozvoliti"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Natrag"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prijenos odobrenja za aplikaciju na sat"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Radi lakšeg postavljanja sata, aplikacije instalirane na satu tokom postavljanja će koristiti ista odobrenja kao i na telefonu.\n\n Ta odobrenja mogu uključivati pristup mikrofonu i lokaciji sata."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index d8834a2b51be..6134390ad5ba 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"Smartphone-Apps streamen"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; Zugriff auf diese Informationen von deinem Smartphone gewähren"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Geräteübergreifende Dienste"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet im Namen deines <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> um die Berechtigung zum Zugriff auf die Fotos, Medien und Benachrichtigungen deines Smartphones"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; Zugriff auf diese Informationen von deinem Smartphone gewähren"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Fotos und Medien"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play-Dienste"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet im Namen deines <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> um die Berechtigung zum Streamen von Apps zwischen deinen Geräten"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Zulassen"</string>
<string name="consent_no" msgid="2640796915611404382">"Nicht zulassen"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Zurück"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"App-Berechtigungen auf Smartwatch übertragen"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Damit sich deine Smartwatch leichter einrichten lässt, erhalten die Apps, die während der Einrichtung auf deiner Smartwatch installiert werden, automatisch die gleichen Berechtigungen wie deine Smartphone-Apps.\n\n Zu diesen Berechtigungen kann der Zugriff auf das Mikrofon und den Standort deiner Smartwatch gehören."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index cf08be098b63..fff1e5e64a05 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
<string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Back"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
index cf08be098b63..fff1e5e64a05 100644
--- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
<string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Back"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
index cf08be098b63..fff1e5e64a05 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
<string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Back"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
index cf08be098b63..fff1e5e64a05 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
<string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Back"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index a4a1cc4c0919..6012c6c91a9f 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"તમારા ફોનની ઍપ સ્ટ્રીમ કરો"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"તમારા ફોનમાંથી આ માહિતી ઍક્સેસ કરવા માટે, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને મંજૂરી આપો"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ક્રોસ-ડિવાઇસ સેવાઓ"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> તમારા <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> વતી તમારા ફોનના ફોટા, મીડિયા અને નોટિફિકેશન ઍક્સેસ કરવાની પરવાનગીની વિનંતી કરી રહી છે"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"તમારા ફોનમાંથી આ માહિતી ઍક્સેસ કરવા માટે, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને મંજૂરી આપો"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"ફોટા અને મીડિયા"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play સેવાઓ"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> તમારા <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> વતી તમારા ડિવાઇસ વચ્ચે ઍપ સ્ટ્રીમ કરવાની પરવાનગીની વિનંતી કરી રહી છે"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"મંજૂરી આપો"</string>
<string name="consent_no" msgid="2640796915611404382">"મંજૂરી આપશો નહીં"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"પાછળ"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"તમારી ઘડિયાળમાં ઍપ પરવાનગીઓ ટ્રાન્સફર કરો"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"તમારી ઘડિયાળનું સેટઅપ કરવાનું સરળ બનાવવા માટે, સેટઅપ દરમિયાન તમારી ઘડિયાળ પર ઇન્સ્ટૉલ કરેલી ઍપ દ્વારા તમારા ફોન પર મળેલી પરવાનગીઓનો ઉપયોગ કરવામાં આવશે.\n\n આ પરવાનગીઓમાં તમારી ઘડિયાળના માઇક્રોફોન અને સ્થાન સંબંધિત માહિતીનો ઍક્સેસ શામેલ હોઈ શકે છે."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index 4e9c838722c7..aa0628ebb734 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"अपने फ़ोन के ऐप्लिकेशन को स्ट्रीम करें"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिवाइस से जुड़ी सेवाएं"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> की ओर से, फ़ोन में मौजूद फ़ोटो, मीडिया, और सूचनाओं को ऐक्सेस करने की अनुमति मांग रहा है"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"फ़ोटो और मीडिया"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play सेवाएं"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> की ओर से, डिवाइसों के बीच ऐप्लिकेशन को स्ट्रीम करने की अनुमति मांग रहा है"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"अनुमति दें"</string>
<string name="consent_no" msgid="2640796915611404382">"अनुमति न दें"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"वापस जाएं"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"ऐप्लिकेशन से जुड़ी अनुमतियों को अपनी वॉच में ट्रांसफ़र करें"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"वॉच को सेट अप करने की प्रोसेस को आसान बनाने के लिए, उस पर इंस्टॉल किए गए ऐप्लिकेशन को भी वही अनुमतियां मिलेंगी जो आपने उन ऐप्लिकेशन को फ़ोन पर दी होंगी.\n\n इन अनुमतियों में, आपकी वॉच के माइक्रोफ़ोन और जगह की जानकारी का ऐक्सेस शामिल हो सकता है."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index 3c610e07d917..f5cd4281671c 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"Streaming aplikacija vašeg telefona"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Omogućite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa informacijama s vašeg telefona"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na različitim uređajima"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> da pristupi fotografijama, medijskim sadržajima i obavijestima na telefonu"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Omogućite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa informacijama s vašeg telefona"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Fotografije i mediji"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Usluge za Google Play"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za streamanje aplikacija između vaših uređaja"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Dopusti"</string>
<string name="consent_no" msgid="2640796915611404382">"Nemoj dopustiti"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Natrag"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prijenos dopuštenja aplikacije na sat"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Kako bi postavljanje sata bilo jednostavnije, aplikacije instalirane na satu će tijekom postavljanja upotrebljavati ista dopuštenja kao telefon.\n\n Ta dopuštenja mogu uključivati pristup mikrofonu i lokaciji sata."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index 7ba67a697640..3c71300fad9c 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"ನಿಮ್ಮ ಫೋನ್‍ನ ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಿ"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ಈ ಮಾಹಿತಿಯನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ಕ್ರಾಸ್-ಸಾಧನ ಸೇವೆಗಳು"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"ನಿಮ್ಮ ಫೋನ್‌ನ ಫೋಟೋಗಳು, ಮೀಡಿಯಾ ಮತ್ತು ಅಧಿಸೂಚನೆಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನ ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸಿಕೊಳ್ಳುತ್ತಿದೆ"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ಈ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"ಫೋಟೋಗಳು ಮತ್ತು ಮಾಧ್ಯಮ"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play ಸೇವೆಗಳು"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"ನಿಮ್ಮ ಸಾಧನಗಳ ನಡುವೆ ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನ ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸಿಕೊಳ್ಳುತ್ತಿದೆ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"ಅನುಮತಿಸಿ"</string>
<string name="consent_no" msgid="2640796915611404382">"ಅನುಮತಿಸಬೇಡಿ"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"ಹಿಂದೆ"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"ಆ್ಯಪ್ ಅನುಮತಿಗಳನ್ನು ನಿಮ್ಮ ವಾಚ್‌ಗೆ ವರ್ಗಾವಣೆ ಮಾಡಿ"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"ನಿಮ್ಮ ವಾಚ್ ಸೆಟಪ್ ಮಾಡುವುದನ್ನು ಸುಲಭವಾಗಿಸಲು, ಸೆಟಪ್‌ನ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ ವಾಚ್‌ನಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿದ ಆ್ಯಪ್‌ಗಳು, ನಿಮ್ಮ ಫೋನ್‌ನಲ್ಲಿನ ಅನುಮತಿಗಳನ್ನೇ ಬಳಸಿಕೊಳ್ಳುತ್ತವೆ.\n\n ಈ ಅನುಮತಿಗಳು ನಿಮ್ಮ ವಾಚ್‌ನ ಮೈಕ್ರೊಫೋನ್ ಮತ್ತು ಸ್ಥಳದ ಪ್ರವೇಶವನ್ನು ಒಳಗೊಳ್ಳಬಹುದು."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index bb198df233f6..7ea24e727a2a 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"Стримувајте ги апликациите на телефонот"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Овозможете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до овие податоци на телефонот"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Повеќенаменски услуги"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на вашиот <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за да пристапува до фотографиите, аудиовизуелните содржини и известувањата на телефонот"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Овозможете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до овие податоци на телефонот"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Аудиовизуелни содржини"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Услуги на Google Play"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на вашиот <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за да стримува апликации помеѓу вашите уреди"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"уред"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string>
<string name="consent_no" msgid="2640796915611404382">"Не дозволувај"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Префрлете ги дозволите за апликациите на вашиот часовник"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"За полесно поставувањето на часовникот, апликациите инсталирани на часовникот при поставувањето ќе ги користат истите дозволи како на телефонот.\n\n Овие дозволи може да опфаќаат пристап до микрофонот и локацијата на часовникот."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index b8c44a5a635e..0de423ca4154 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"നിങ്ങളുടെ ഫോണിലെ ആപ്പുകൾ സ്‌ട്രീം ചെയ്യാൻ"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഈ വിവരങ്ങൾ ആക്‌സസ് ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ആപ്പിനെ അനുവദിക്കുക"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ക്രോസ്-ഉപകരണ സേവനങ്ങൾ"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"നിങ്ങളുടെ ഫോണിലെ ഫോട്ടോകൾ, മീഡിയ, അറിയിപ്പുകൾ എന്നിവ ആക്സസ് ചെയ്യാൻ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ഉപകരണത്തിനു വേണ്ടി <xliff:g id="APP_NAME">%1$s</xliff:g> അനുമതി അഭ്യർത്ഥിക്കുന്നു."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഈ വിവരങ്ങൾ ആക്‌സസ് ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ആപ്പിനെ അനുവദിക്കുക"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"ഫോട്ടോകളും മീഡിയയും"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play സേവനങ്ങൾ"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"നിങ്ങളുടെ ഉപകരണങ്ങളിൽ ഒന്നിൽ നിന്ന് അടുത്തതിലേക്ക് ആപ്പുകൾ സ്ട്രീം ചെയ്യാൻ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ഉപകരണത്തിനു വേണ്ടി <xliff:g id="APP_NAME">%1$s</xliff:g> അനുമതി അഭ്യർത്ഥിക്കുന്നു."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ഉപകരണം"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"അനുവദിക്കുക"</string>
<string name="consent_no" msgid="2640796915611404382">"അനുവദിക്കരുത്"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"മടങ്ങുക"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"നിങ്ങളുടെ വാച്ചിലേക്ക് ആപ്പ് അനുമതികൾ കൈമാറുക"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"നിങ്ങളുടെ വാച്ച് സജ്ജീകരിക്കുന്നത് എളുപ്പമാക്കാൻ, സജ്ജീകരിക്കുമ്പോൾ ഫോണിലുള്ള അതേ അനുമതികൾ നിങ്ങളുടെ വാച്ചിൽ ഇൻസ്റ്റാൾ ചെയ്തിട്ടുള്ള ആപ്പുകൾ ഉപയോഗിക്കും.\n\n ഈ അനുമതികളിൽ നിങ്ങളുടെ വാച്ചിന്റെ മൈക്രോഫോണിലേക്കും ലോക്കേഷനിലേക്കുമുള്ള ആക്‌സസ് ഉൾപ്പെട്ടേക്കാം."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index 7233c04954f4..f4dd0e1e3f21 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"Таны утасны аппуудыг дамжуулах"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д таны утаснаас энэ мэдээлэлд хандахыг зөвшөөрнө үү"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Төхөөрөмж хоорондын үйлчилгээ"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь таны <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-н өмнөөс утасны зураг, медиа болон мэдэгдэлд хандахын тулд зөвшөөрөл хүсэж байна"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д таны утаснаас энэ мэдээлэлд хандахыг зөвшөөрнө үү"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Зураг болон медиа"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play үйлчилгээ"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь таны <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-н өмнөөс төхөөрөмж хооронд апп дамжуулахын тулд зөвшөөрөл хүсэж байна"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Зөвшөөрөх"</string>
<string name="consent_no" msgid="2640796915611404382">"Бүү зөвшөөр"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Буцах"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Цагандаа аппын зөвшөөрлийг шилжүүлэх"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Таны цагийг тохируулахад илүү хялбар болгохын тулд тохируулгын үеэр таны цаган дээр суулгасан аппууд нь утастай тань ижил зөвшөөрлийг ашиглана.\n\n Эдгээр зөвшөөрөлд таны цагийн микрофон болон байршлын хандалт зэрэг багтаж магадгүй."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index efc7412b03d0..a0b561a5ec27 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"Strim apl telefon anda"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengakses maklumat ini daripada telefon anda"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Perkhidmatan silang peranti"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda untuk mengakses foto, media dan pemberitahuan telefon anda"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengakses maklumat ini daripada telefon anda"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Foto dan media"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Perkhidmatan Google Play"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda untuk menstrim apl antara peranti anda"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Benarkan"</string>
<string name="consent_no" msgid="2640796915611404382">"Jangan benarkan"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Kembali"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Pindahkan kebenaran apl pada jam tangan anda"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Untuk memudahkan penyediaan jam tangan anda, apl yang dipasang pada jam tangan anda semasa persediaan akan menggunakan kebenaran yang sama seperti telefon anda.\n\n Kebenaran ini mungkin termasuk akses kepada mikrofon dan lokasi jam tangan anda."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index c14e68269a73..2cfbdbbc885e 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"Să redea în stream aplicațiile telefonului"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permiteți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să acceseze aceste informații de pe telefon"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicii pe mai multe dispozitive"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> de a accesa fotografiile, conținutul media și notificările de pe telefon"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permiteți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să acceseze aceste informații de pe telefon"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Fotografii și media"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Servicii Google Play"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> de a reda în stream aplicații între dispozitivele dvs."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permiteți"</string>
<string name="consent_no" msgid="2640796915611404382">"Nu permiteți"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Înapoi"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferați permisiunile pentru aplicații pe ceas"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Ca să configurați mai ușor ceasul, aplicațiile instalate pe ceas în timpul procesului de configurare vor folosi aceleași permisiuni ca telefonul.\n\n Între acestea se poate număra accesul la microfonul și locația ceasului."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index efa0c76f80c1..3be67ff2837c 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"Стримујте апликације на телефону"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; приступа овим информацијама са телефона"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуге на више уређаја"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> захтева дозволу у име уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за приступ сликама, медијском садржају и обавештењима са телефона"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; приступа овим информацијама са телефона"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Слике и медији"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play услуге"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> захтева дозволу у име уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за стримовање апликација између уређаја"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"уређај"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string>
<string name="consent_no" msgid="2640796915611404382">"Не дозволи"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Пренесите дозволе за апликације на сат"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Да бисмо поједноставили подешавање сата, апликације инсталиране на сату током подешавања ће користити исте дозволе као телефон.\n\n Те дозволе могу да обухватају приступ микрофону и локацији сата."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index f431fe462b9d..ec3289dec687 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"మీ ఫోన్ యాప్‌లను స్ట్రీమ్ చేయండి"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"మీ ఫోన్ నుండి ఈ సమాచారాన్ని యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; యాప్‌ను అనుమతించండి"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"క్రాస్-డివైజ్ సర్వీసులు"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> మీ ఫోన్ ఫోటోలు, మీడియా, నోటిఫికేషన్‌లను యాక్సెస్ చేయడానికి మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> తరపున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"మీ ఫోన్ నుండి ఈ సమాచారాన్ని యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; యాప్‌ను అనుమతించండి"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"ఫోటోలు, మీడియా"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play సర్వీసులు"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"మీ పరికరాల మధ్య యాప్‌లను స్ట్రీమ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> తరపున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"పరికరం"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"అనుమతించు"</string>
<string name="consent_no" msgid="2640796915611404382">"అనుమతించవద్దు"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"వెనుకకు"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"మీ వాచ్‌కు యాప్ అనుమతులను బదిలీ చేయండి"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"మీ వాచ్‌ను సెటప్ చేయడాన్ని సులభతరం చేయడానికి, సెటప్ సమయంలో మీ వాచ్‌లో ఇన్‌స్టాల్ చేయబడిన యాప్‌లు మీ ఫోన్‌లో యాప్‌లకు ఉన్న అవే అనుమతులను ఉపయోగిస్తాయి.\n\n ఈ అనుమతులతో మీ వాచ్ మైక్రోఫోన్, అలాగే లొకేషన్ కూడా ఉండవచ్చు."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index 7fec8857c9f0..2b4742612858 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"สตรีมแอปของโทรศัพท์คุณ"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; เข้าถึงข้อมูลนี้จากโทรศัพท์ของคุณ"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"บริการหลายอุปกรณ์"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> เพื่อเข้าถึงรูปภาพ สื่อ และการแจ้งเตือนในโทรศัพท์ของคุณ"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; เข้าถึงข้อมูลนี้จากโทรศัพท์ของคุณ"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"รูปภาพและสื่อ"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"บริการ Google Play"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> เพื่อสตรีมแอประหว่างอุปกรณ์ต่างๆ ของคุณ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"อุปกรณ์"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"อนุญาต"</string>
<string name="consent_no" msgid="2640796915611404382">"ไม่อนุญาต"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"กลับ"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"โอนสิทธิ์ของแอปไปยังนาฬิกา"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"แอปที่ติดตั้งในนาฬิการะหว่างการตั้งค่าจะใช้สิทธิ์เดียวกันกับโทรศัพท์เพื่อให้การตั้งค่านาฬิกาง่ายขึ้น\n\n สิทธิ์เหล่านี้อาจรวมการเข้าถึงไมโครโฟนและตำแหน่งของนาฬิกา"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index eddd71108dd6..15953a6065c4 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"I-stream ang mga app ng iyong telepono"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na i-access ang impormasyong ito sa iyong telepono"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Mga cross-device na serbisyo"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"Ang <xliff:g id="APP_NAME">%1$s</xliff:g> ay humihiling ng pahintulot sa ngalan ng iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para i-access ang mga larawan, media, at notification ng telepono mo"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na i-access ang impormasyon sa iyong telepono"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Mga larawan at media"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Mga serbisyo ng Google Play"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"Ang <xliff:g id="APP_NAME">%1$s</xliff:g> ay humihiling ng pahintulot sa ngalan ng iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para mag-stream ng mga app sa pagitan ng mga device mo"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Payagan"</string>
<string name="consent_no" msgid="2640796915611404382">"Huwag payagan"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Bumalik"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Ilipat sa iyong relo ang mga pahintulot sa app"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Para gawing mas madali na i-set up ang iyong relo, gagamitin ng mga app na naka-install sa relo mo sa oras ng pag-set up ang mga pahintulot na ginagamit din sa iyong telepono.\n\n Posibleng kasama sa mga pahintulot na ito ang access sa mikropono at lokasyon ng iyong relo."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index 3f5031f87432..a86eec2b085d 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -26,8 +26,7 @@
<string name="permission_apps_summary" msgid="798718816711515431">"Sakaza ama-app wefoni yakho"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Vumela i-&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifinyelele lolu lwazi kusukela efonini yakho"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Amasevisi amadivayisi amaningi"</string>
- <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
- <skip />
+ <string name="helper_summary_app_streaming" msgid="7380294597268573523">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho ukuze ifinyelele izithombe zefoni yakho, imidiya nezaziso"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukufinyelela lolu lwazi kusuka efonini yakho"</string>
@@ -37,14 +36,12 @@
<string name="permission_storage" msgid="6831099350839392343">"Izithombe nemidiya"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Amasevisi we-Google Play"</string>
- <!-- no translation found for helper_summary_computer (1676407599909474428) -->
- <skip />
+ <string name="helper_summary_computer" msgid="1676407599909474428">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho ukuze isakaze-bukhoma ama-app phakathi kwamadivayisi akho"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"idivayisi"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Vumela"</string>
<string name="consent_no" msgid="2640796915611404382">"Ungavumeli"</string>
- <!-- no translation found for consent_back (2560683030046918882) -->
- <skip />
+ <string name="consent_back" msgid="2560683030046918882">"Emuva"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Dlulisela izimvume ze-app ewashini lakho"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Ukuze wenze kube lula ukusetha iwashi lakho, ama-app afakwe ewashini lakho phakathi nokusetha azosebenzisa izimvume ezifanayo nezefoni yakho.\n\n Lezi zimvume zingabandakanya ukufinyelela kumakrofoni nendawo yewashi lakho."</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 02128d480678..3a3565941489 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -112,18 +112,20 @@ public class DynamicSystemInstallationService extends Service
private static final int EVENT_DSU_INSTALL_FAILED = 120002;
protected static void logEventProgressUpdate(
- String partition,
- long installedSize,
- long partitionSize,
+ String partitionName,
+ long installedBytes,
+ long totalBytes,
int partitionNumber,
- int totalPartitionNumber) {
+ int totalPartitionNumber,
+ int totalProgressPercentage) {
EventLog.writeEvent(
EVENT_DSU_PROGRESS_UPDATE,
- partition,
- installedSize,
- partitionSize,
+ partitionName,
+ installedBytes,
+ totalBytes,
partitionNumber,
- totalPartitionNumber);
+ totalPartitionNumber,
+ totalProgressPercentage);
}
protected static void logEventComplete() {
@@ -231,10 +233,11 @@ public class DynamicSystemInstallationService extends Service
public void onProgressUpdate(InstallationAsyncTask.Progress progress) {
logEventProgressUpdate(
progress.partitionName,
- progress.installedSize,
- progress.partitionSize,
+ progress.installedBytes,
+ progress.totalBytes,
progress.partitionNumber,
- progress.totalPartitionNumber);
+ progress.totalPartitionNumber,
+ progress.totalProgressPercentage);
mInstallTaskProgress = progress;
postStatus(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED, null);
@@ -483,23 +486,46 @@ public class DynamicSystemInstallationService extends Service
switch (status) {
case STATUS_IN_PROGRESS:
- builder.setContentText(getString(R.string.notification_install_inprogress));
+ String msgInProgress = getString(R.string.notification_install_inprogress);
- if (mInstallTaskProgress != null) {
- int max = 1024;
- int progress = 0;
+ if (mInstallTaskProgress == null) {
+ builder.setContentText(msgInProgress);
+ } else {
+ if (mInstallTaskProgress.totalPartitionNumber > 0) {
+ builder.setContentText(
+ String.format(
+ "%s: %s partition [%d/%d]",
+ msgInProgress,
+ mInstallTaskProgress.partitionName,
+ mInstallTaskProgress.partitionNumber,
+ mInstallTaskProgress.totalPartitionNumber));
+
+ // totalProgressPercentage is defined iff totalPartitionNumber is defined
+ builder.setProgress(
+ 100,
+ mInstallTaskProgress.totalProgressPercentage,
+ /* indeterminate = */ false);
+ } else {
+ builder.setContentText(
+ String.format(
+ "%s: %s partition",
+ msgInProgress, mInstallTaskProgress.partitionName));
+
+ int max = 1024;
+ int progress = 0;
- int currentMax = max >> mInstallTaskProgress.partitionNumber;
- progress = max - currentMax * 2;
+ int currentMax = max >> mInstallTaskProgress.partitionNumber;
+ progress = max - currentMax * 2;
- long currentProgress =
- (mInstallTaskProgress.installedSize >> 20)
- * currentMax
- / Math.max(mInstallTaskProgress.partitionSize >> 20, 1);
+ long currentProgress =
+ (mInstallTaskProgress.installedBytes >> 20)
+ * currentMax
+ / Math.max(mInstallTaskProgress.totalBytes >> 20, 1);
- progress += (int) currentProgress;
+ progress += (int) currentProgress;
- builder.setProgress(max, progress, false);
+ builder.setProgress(max, progress, false);
+ }
}
builder.addAction(new Notification.Action.Builder(
null, getString(R.string.notification_action_cancel),
@@ -609,10 +635,11 @@ public class DynamicSystemInstallationService extends Service
if (status == STATUS_IN_PROGRESS && mInstallTaskProgress != null) {
msg.append(
String.format(
- ", partition name: %s, progress: %d/%d",
+ ", partition name: %s, progress: %d/%d, total_progress: %d%%",
mInstallTaskProgress.partitionName,
- mInstallTaskProgress.installedSize,
- mInstallTaskProgress.partitionSize));
+ mInstallTaskProgress.installedBytes,
+ mInstallTaskProgress.totalBytes,
+ mInstallTaskProgress.totalProgressPercentage));
}
if (detail != null) {
msg.append(", detail: " + detail);
@@ -639,7 +666,7 @@ public class DynamicSystemInstallationService extends Service
// TODO: send more info to the clients
if (mInstallTaskProgress != null) {
bundle.putLong(
- DynamicSystemClient.KEY_INSTALLED_SIZE, mInstallTaskProgress.installedSize);
+ DynamicSystemClient.KEY_INSTALLED_SIZE, mInstallTaskProgress.installedBytes);
}
if (detail != null) {
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags
index eae9de937700..407314384be8 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags
@@ -2,6 +2,6 @@
option java_package com.android.dynsystem
-120000 dsu_progress_update (partition|3),(installed_size|2|5),(partition_size|2|5),(partition_number|1|5),(total_partition_number|1|5)
+120000 dsu_progress_update (partition_name|3),(installed_bytes|2|5),(total_bytes|2|5),(partition_number|1|5),(total_partition_number|1|5),(total_progress_percentage|1|5)
120001 dsu_install_complete
120002 dsu_install_failed (cause|3)
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index 998aeeab4b47..38d851eb76aa 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -41,6 +41,10 @@ import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -51,8 +55,8 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
private static final String TAG = "InstallationAsyncTask";
private static final int MIN_SHARED_MEMORY_SIZE = 8 << 10; // 8KiB
- private static final int MAX_SHARED_MEMORY_SIZE = 1024 << 10; // 1MiB
- private static final int DEFAULT_SHARED_MEMORY_SIZE = 64 << 10; // 64KiB
+ private static final int MAX_SHARED_MEMORY_SIZE = 8 << 20; // 8MiB
+ private static final int DEFAULT_SHARED_MEMORY_SIZE = 512 << 10; // 512KiB
private static final String SHARED_MEMORY_SIZE_PROP =
"dynamic_system.data_transfer.shared_memory.size";
@@ -113,22 +117,25 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
static class Progress {
public final String partitionName;
- public final long installedSize;
- public final long partitionSize;
+ public final long installedBytes;
+ public final long totalBytes;
public final int partitionNumber;
public final int totalPartitionNumber;
+ public final int totalProgressPercentage;
Progress(
String partitionName,
- long installedSize,
- long partitionSize,
+ long installedBytes,
+ long totalBytes,
int partitionNumber,
- int totalPartitionNumber) {
+ int totalPartitionNumber,
+ int totalProgressPercentage) {
this.partitionName = partitionName;
- this.installedSize = installedSize;
- this.partitionSize = partitionSize;
+ this.installedBytes = installedBytes;
+ this.totalBytes = totalBytes;
this.partitionNumber = partitionNumber;
this.totalPartitionNumber = totalPartitionNumber;
+ this.totalProgressPercentage = totalProgressPercentage;
}
}
@@ -149,20 +156,28 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
private final ProgressListener mListener;
private final boolean mIsNetworkUrl;
private final boolean mIsDeviceBootloaderUnlocked;
+ private final boolean mWantScratchPartition;
private DynamicSystemManager.Session mInstallationSession;
private KeyRevocationList mKeyRevocationList;
private boolean mIsZip;
private boolean mIsCompleted;
-
- private String mPartitionName;
- private long mPartitionSize;
- private int mPartitionNumber;
- private int mTotalPartitionNumber;
-
private InputStream mStream;
private ZipFile mZipFile;
+ private static final double PROGRESS_READONLY_PARTITION_WEIGHT = 0.8;
+ private static final double PROGRESS_WRITABLE_PARTITION_WEIGHT = 0.2;
+
+ private String mProgressPartitionName;
+ private long mProgressTotalBytes;
+ private int mProgressPartitionNumber;
+ private boolean mProgressPartitionIsReadonly;
+ private int mProgressCompletedReadonlyPartitions;
+ private int mProgressCompletedWritablePartitions;
+ private int mTotalReadonlyPartitions;
+ private int mTotalWritablePartitions;
+ private int mTotalPartitionNumber;
+
InstallationAsyncTask(
String url,
String dsuSlot,
@@ -193,21 +208,18 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
(pdbManager != null)
&& (pdbManager.getFlashLockState()
== PersistentDataBlockManager.FLASH_LOCK_UNLOCKED);
+ mWantScratchPartition = Build.IS_DEBUGGABLE;
}
@Override
protected Throwable doInBackground(String... voids) {
Log.d(TAG, "Start doInBackground(), URL: " + mUrl);
- final boolean wantScratchPartition = Build.IS_DEBUGGABLE;
try {
// call DynamicSystemManager to cleanup stuff
mDynSystem.remove();
verifyAndPrepare();
- if (wantScratchPartition) {
- ++mTotalPartitionNumber;
- }
mDynSystem.startInstallation(mDsuSlot);
@@ -226,7 +238,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
return null;
}
- if (wantScratchPartition) {
+ if (mWantScratchPartition) {
// If host is debuggable, then install a scratch partition so that we can do
// adb remount in the guest system.
try {
@@ -290,14 +302,54 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
}
@Override
- protected void onProgressUpdate(Long... installedSize) {
+ protected void onProgressUpdate(Long... progress) {
+ final long installedBytes = progress[0];
+ int totalProgressPercentage = 0;
+ if (mTotalPartitionNumber > 0) {
+ final double readonlyPartitionWeight =
+ mTotalReadonlyPartitions > 0
+ ? PROGRESS_READONLY_PARTITION_WEIGHT / mTotalReadonlyPartitions
+ : 0;
+ final double writablePartitionWeight =
+ mTotalWritablePartitions > 0
+ ? PROGRESS_WRITABLE_PARTITION_WEIGHT / mTotalWritablePartitions
+ : 0;
+ double totalProgress = 0.0;
+ if (mProgressTotalBytes > 0) {
+ totalProgress +=
+ (mProgressPartitionIsReadonly
+ ? readonlyPartitionWeight
+ : writablePartitionWeight)
+ * installedBytes
+ / mProgressTotalBytes;
+ }
+ totalProgress += readonlyPartitionWeight * mProgressCompletedReadonlyPartitions;
+ totalProgress += writablePartitionWeight * mProgressCompletedWritablePartitions;
+ totalProgressPercentage = (int) (totalProgress * 100);
+ }
mListener.onProgressUpdate(
new Progress(
- mPartitionName,
- installedSize[0],
- mPartitionSize,
- mPartitionNumber,
- mTotalPartitionNumber));
+ mProgressPartitionName,
+ installedBytes,
+ mProgressTotalBytes,
+ mProgressPartitionNumber,
+ mTotalPartitionNumber,
+ totalProgressPercentage));
+ }
+
+ private void initPartitionProgress(String partitionName, long totalBytes, boolean readonly) {
+ if (mProgressPartitionNumber > 0) {
+ // Assume previous partition completed successfully.
+ if (mProgressPartitionIsReadonly) {
+ ++mProgressCompletedReadonlyPartitions;
+ } else {
+ ++mProgressCompletedWritablePartitions;
+ }
+ }
+ mProgressPartitionName = partitionName;
+ mProgressTotalBytes = totalBytes;
+ mProgressPartitionIsReadonly = readonly;
+ ++mProgressPartitionNumber;
}
private void verifyAndPrepare() throws Exception {
@@ -314,16 +366,12 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
throw new UnsupportedFormatException(
String.format(Locale.US, "Unsupported file format: %s", mUrl));
}
- // At least two partitions, {system, userdata}
- mTotalPartitionNumber = 2;
if (mIsNetworkUrl) {
mStream = new URL(mUrl).openStream();
} else if (URLUtil.isFileUrl(mUrl)) {
if (mIsZip) {
mZipFile = new ZipFile(new File(new URL(mUrl).toURI()));
- // {*.img in zip} + {userdata}
- mTotalPartitionNumber = calculateNumberOfImagesInLocalZip(mZipFile) + 1;
} else {
mStream = new URL(mUrl).openStream();
}
@@ -334,6 +382,32 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
String.format(Locale.US, "Unsupported URL: %s", mUrl));
}
+ boolean hasTotalPartitionNumber = false;
+ if (mIsZip) {
+ if (mZipFile != null) {
+ // {*.img in zip} + {userdata}
+ hasTotalPartitionNumber = true;
+ mTotalReadonlyPartitions = calculateNumberOfImagesInLocalZip(mZipFile);
+ mTotalWritablePartitions = 1;
+ } else {
+ // TODO: Come up with a way to retrieve the number of total partitions from
+ // network URL.
+ }
+ } else {
+ // gzip has exactly two partitions, {system, userdata}
+ hasTotalPartitionNumber = true;
+ mTotalReadonlyPartitions = 1;
+ mTotalWritablePartitions = 1;
+ }
+
+ if (hasTotalPartitionNumber) {
+ if (mWantScratchPartition) {
+ // {scratch}
+ ++mTotalWritablePartitions;
+ }
+ mTotalPartitionNumber = mTotalReadonlyPartitions + mTotalWritablePartitions;
+ }
+
try {
String listUrl = mContext.getString(R.string.key_revocation_list_url);
mKeyRevocationList = KeyRevocationList.fromUrl(new URL(listUrl));
@@ -370,9 +444,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
}
};
- mPartitionName = partitionName;
- mPartitionSize = partitionSize;
- ++mPartitionNumber;
+ initPartitionProgress(partitionName, partitionSize, /* readonly = */ false);
publishProgress(/* installedSize = */ 0L);
long prevInstalledSize = 0;
@@ -396,6 +468,10 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
}
}
+ if (prevInstalledSize != partitionSize) {
+ publishProgress(partitionSize);
+ }
+
if (mInstallationSession == null) {
throw new IOException(
"Failed to start installation with requested size: " + partitionSize);
@@ -416,7 +492,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
installWritablePartition("userdata", mUserdataSize);
}
- private void installImages() throws IOException, ImageValidationException {
+ private void installImages() throws ExecutionException, IOException, ImageValidationException {
if (mStream != null) {
if (mIsZip) {
installStreamingZipUpdate();
@@ -428,7 +504,8 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
}
}
- private void installStreamingGzUpdate() throws IOException, ImageValidationException {
+ private void installStreamingGzUpdate()
+ throws ExecutionException, IOException, ImageValidationException {
Log.d(TAG, "To install a streaming GZ update");
installImage("system", mSystemSize, new GZIPInputStream(mStream));
}
@@ -456,7 +533,8 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
return total;
}
- private void installStreamingZipUpdate() throws IOException, ImageValidationException {
+ private void installStreamingZipUpdate()
+ throws ExecutionException, IOException, ImageValidationException {
Log.d(TAG, "To install a streaming ZIP update");
ZipInputStream zis = new ZipInputStream(mStream);
@@ -476,7 +554,8 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
}
}
- private void installLocalZipUpdate() throws IOException, ImageValidationException {
+ private void installLocalZipUpdate()
+ throws ExecutionException, IOException, ImageValidationException {
Log.d(TAG, "To install a local ZIP update");
Enumeration<? extends ZipEntry> entries = mZipFile.entries();
@@ -497,7 +576,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
}
private void installImageFromAnEntry(ZipEntry entry, InputStream is)
- throws IOException, ImageValidationException {
+ throws ExecutionException, IOException, ImageValidationException {
String name = entry.getName();
Log.d(TAG, "ZipEntry: " + name);
@@ -509,7 +588,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
}
private void installImage(String partitionName, long uncompressedSize, InputStream is)
- throws IOException, ImageValidationException {
+ throws ExecutionException, IOException, ImageValidationException {
SparseInputStream sis = new SparseInputStream(new BufferedInputStream(is));
@@ -559,33 +638,59 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
mInstallationSession.setAshmem(pfd, memoryFile.length());
- mPartitionName = partitionName;
- mPartitionSize = partitionSize;
- ++mPartitionNumber;
+ initPartitionProgress(partitionName, partitionSize, /* readonly = */ true);
publishProgress(/* installedSize = */ 0L);
long prevInstalledSize = 0;
long installedSize = 0;
byte[] bytes = new byte[memoryFile.length()];
- int numBytesRead;
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future<Boolean> submitPromise = null;
+
+ while (true) {
+ final int numBytesRead = sis.read(bytes, 0, bytes.length);
+
+ if (submitPromise != null) {
+ // Wait until the previous submit task is complete.
+ while (true) {
+ try {
+ if (!submitPromise.get()) {
+ throw new IOException("Failed submitFromAshmem() to DynamicSystem");
+ }
+ break;
+ } catch (InterruptedException e) {
+ // Ignore.
+ }
+ }
+
+ // Publish the progress of the previous submit task.
+ if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
+ publishProgress(installedSize);
+ prevInstalledSize = installedSize;
+ }
+ }
+
+ // Ensure the previous submit task (submitPromise) is complete before exiting the loop.
+ if (numBytesRead < 0) {
+ break;
+ }
- while ((numBytesRead = sis.read(bytes, 0, bytes.length)) != -1) {
if (isCancelled()) {
return;
}
memoryFile.writeBytes(bytes, 0, 0, numBytesRead);
+ submitPromise =
+ executor.submit(() -> mInstallationSession.submitFromAshmem(numBytesRead));
- if (!mInstallationSession.submitFromAshmem(numBytesRead)) {
- throw new IOException("Failed write() to DynamicSystem");
- }
-
+ // Even though we update the bytes counter here, the actual progress is updated only
+ // after the submit task (submitPromise) is complete.
installedSize += numBytesRead;
+ }
- if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
- publishProgress(installedSize);
- prevInstalledSize = installedSize;
- }
+ // Ensure a 100% mark is published.
+ if (prevInstalledSize != partitionSize) {
+ publishProgress(partitionSize);
}
AvbPublicKey avbPublicKey = new AvbPublicKey();
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index 7b526bb5193c..9172d1c58230 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -106,6 +106,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Dat werkte niet. Probeer het opnieuw."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Opnieuw proberen"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Deze printer is momenteel niet beschikbaar."</string>
- <string name="print_cannot_load_page" msgid="6179560924492912009">"Kan voorbeeld niet weergeven"</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Kan voorbeeld niet bekijken"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Voorbeeld voorbereiden…"</string>
</resources>
diff --git a/packages/SettingsLib/res/drawable/ic_qr_code_scanner.xml b/packages/SettingsLib/res/drawable/ic_qr_code_scanner.xml
new file mode 100644
index 000000000000..f6f63c5ae7fa
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_qr_code_scanner.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp"
+ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path android:fillColor="@android:color/white"
+ android:pathData="M2,7V2H7V4H4V7ZM2,22V17H4V20H7V22ZM17,22V20H20V17H22V22ZM20,7V4H17V2H22V7ZM17.5,17.5H19V19H17.5ZM17.5,14.5H19V16H17.5ZM16,16H17.5V17.5H16ZM14.5,17.5H16V19H14.5ZM13,16H14.5V17.5H13ZM16,13H17.5V14.5H16ZM14.5,14.5H16V16H14.5ZM13,13H14.5V14.5H13ZM19,5V11H13V5ZM11,13V19H5V13ZM11,5V11H5V5ZM9.5,17.5V14.5H6.5V17.5ZM9.5,9.5V6.5H6.5V9.5ZM17.5,9.5V6.5H14.5V9.5Z"/>
+</vector> \ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/qrcode_scan_mode_activity.xml b/packages/SettingsLib/res/layout/qrcode_scan_mode_activity.xml
new file mode 100644
index 000000000000..f0a182b3d67b
--- /dev/null
+++ b/packages/SettingsLib/res/layout/qrcode_scan_mode_activity.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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:id="@+id/root"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/fragment_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
+</LinearLayout>
diff --git a/packages/SettingsLib/res/layout/qrcode_scanner_fragment.xml b/packages/SettingsLib/res/layout/qrcode_scanner_fragment.xml
new file mode 100644
index 000000000000..e071f4c469a6
--- /dev/null
+++ b/packages/SettingsLib/res/layout/qrcode_scanner_fragment.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/sud_layout_icon_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="3"
+ android:layout_marginBottom="35dp">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:gravity="center"
+ android:orientation="vertical">
+ <ImageView
+ android:id="@+id/sud_layout_icon"
+ android:src="@drawable/ic_qr_code_scanner"
+ android:tint="?androidprv:attr/colorAccentPrimaryVariant"
+ android:layout_width="@dimen/qrcode_icon_size"
+ android:layout_height="@dimen/qrcode_icon_size"
+ android:contentDescription="@null"/>
+
+ <TextView
+ android:id="@+id/sud_layout_title"
+ style="@style/QrCodeScanner"
+ android:textSize="24sp"
+ android:text="@string/bt_le_audio_scan_qr_code"
+ android:gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="19dp"/>
+
+ <TextView
+ android:id="@+id/sud_layout_subtitle"
+ style="@style/QrCodeScanner"
+ android:text="@string/bt_le_audio_scan_qr_code_scanner"
+ android:gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"/>
+ </LinearLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="7"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:gravity="center"
+ android:clipChildren="true">
+ <TextureView
+ android:id="@+id/preview_view"
+ android:layout_marginStart="@dimen/qrcode_preview_margin"
+ android:layout_marginEnd="@dimen/qrcode_preview_margin"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qrcode_preview_size"/>
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/error_message"
+ style="@style/TextAppearance.ErrorText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:layout_marginStart="?attr/sudMarginStart"
+ android:layout_marginEnd="?attr/sudMarginEnd"
+ android:gravity="center"
+ android:visibility="invisible"/>
+
+ </LinearLayout>
+
+
+</LinearLayout>
+
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 514cd42e8a0d..56e88cf0dddd 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"مستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"مستوى البطارية: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، المعدّل: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"نشط"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"السمّاعة الطبية اليسرى فقط مفعَّلة"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"السمّاعة الطبية اليمنى فقط مفعَّلة"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"السمّاعتان اليسرى واليمنى مفعَّلتان"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"الإعدادات الصوتية للوسائط"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"المكالمات الهاتفية"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"نقل الملف"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 9da4e5392d54..bb8fb28856d9 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰিব পৰা নগ’ল"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"নতুন অতিথি সৃষ্টি কৰিব পৰা নগ’ল"</string>
<string name="user_nickname" msgid="262624187455825083">"উপনাম"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"ব্যৱহাৰকাৰী যোগ দিয়ক"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ কৰক"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি আঁতৰাওক"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"অতিথিৰ ছেশ্বন ৰিছেট কৰক"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"অতিথিৰ ছেশ্বন ৰিছেট কৰিবনে?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"অতিথি আঁতৰাবনে?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"ৰিছেট কৰক"</string>
<string name="guest_resetting" msgid="7822120170191509566">"অতিথিৰ ছেশ্বন ৰিছেট কৰি থকা হৈছে…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"এখন ফট’ তোলক"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"এখন প্ৰতিচ্ছবি বাছনি কৰক"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ফট’ বাছনি কৰক"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"অতি বেছি ভুল প্ৰয়াস। ডিভাইচটোৰ ডেটা মচা হ’ব।"</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"অতি বেছি ভুল প্ৰয়াস। এই ব্যৱহাৰকাৰীক মচা হ’ব।"</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"অতি বেছি ভুল প্ৰয়াস। এই কৰ্মস্থানৰ প্ৰ’ফাইলটো আৰু তাৰ লগত জড়িত ডেটা মচা হ’ব।"</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"অগ্ৰাহ্য কৰক"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ডিভাইচ ডিফ’ল্ট"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"অক্ষম কৰা আছে"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"সক্ষম কৰা আছে"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index d2a4fd7367b2..ece3956fbe4d 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Yeni istifadəçi yaratmaq alınmadı"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Yeni qonaq yaratmaq alınmadı"</string>
<string name="user_nickname" msgid="262624187455825083">"Ləqəb"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"İstifadəçi əlavə edin"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Qonaq əlavə edin"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Qonağı silin"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Qonaq sessiyasını sıfırlayın"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Qonaq məlumatı sıfırlansın?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Qonaq silinsin?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Sıfırlayın"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Qonaq məlumatı sıfırlanır…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Foto çəkin"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Şəkil seçin"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Foto seçin"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Həddindən artıq yanlış cəhd. Bu cihazın datası silinəcək."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Həddindən artıq yanlış cəhd. Bu istifadəçi silinəcək."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Həddindən artıq yanlış cəhd. Bu iş profili və datası silinəcək."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Qapadın"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Cihaz defoltu"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiv"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 6d78085e6c35..e7c281397e2d 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Nivo baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterije, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterije"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktivan"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktivno, samo s leve strane"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktivno, s desne strane"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktivno, s leve i desne strane"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Zvuk medija"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonski pozivi"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Prenos datoteke"</string>
@@ -592,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Pravljenje novog korisnika nije uspelo"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Pravljenje novog gosta nije uspelo"</string>
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"Dodaj korisnika"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Resetuj sesiju gosta"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Želite li da resetujete sesiju gosta?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Želite li da uklonite gosta?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Resetuj"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Sesija gosta se resetuje…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Slikaj"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Izaberite sliku"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Previše netačnih pokušaja. Izbrisaćemo podatke sa ovog uređaja."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Previše netačnih pokušaja. Izbrisaćemo ovog korisnika."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Previše netačnih pokušaja. Izbrisaćemo ovaj poslovni profil i njegove podatke."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Odbaci"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Podrazumevano za uređaj"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogućeno"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index d7842dec54d0..ddc155c37d60 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Узровень зараду: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Л: акумулятар: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, П: акумулятар: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Уключана"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Уключана, толькі для левага вуха"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Уключана, толькі для правага вуха"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Уключана, для левага і правага вуха"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Аўдыя медыяфайлаў"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Тэлефонныя выклікі"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Перадача файлаў"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 780068fca09d..0398c1851da6 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Батерия: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Л: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батерия. Д: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батерия"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Активно"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Активно – само лявото"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Активно – само дясното"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Активно – лявото и дясното"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Мултимедийно аудио"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Телефонни обаждания"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Прехвърляне на файл"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index e7b4cebda6be..a0cf42bb79cd 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"চার্জ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ব্যাটারি, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ব্যাটারি"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"চালু আছে"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"শুধুমাত্র বাঁদিকের হিয়ারিং এড অ্যাক্টিভ"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"শুধুমাত্র ডানদিকের হিয়ারিং এড অ্যাক্টিভ"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"বাঁ ও ডানদিকের হিয়ারিং এড, অ্যাক্টিভ"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"মিডিয়া অডিও"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"ফোন কল"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ফাইল স্থানান্তর"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 5700cac71078..faa7333e7dfd 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -109,9 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: baterija <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: baterija <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktivan"</string>
- <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktivno, samo lijevo"</string>
- <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktivno, samo desno"</string>
- <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktivno, lijevo i desno"</string>
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktivno, samo lijevi"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktivno, samo desni"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktivno, lijevi i desni"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Zvuk medija"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonski pozivi"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Prenošenje fajla"</string>
@@ -173,11 +173,11 @@
<string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Uklonjene aplikacije"</string>
<string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Uklonjene aplikacije i korisnici"</string>
<string name="data_usage_ota" msgid="7984667793701597001">"Ažuriranja sistema"</string>
- <string name="tether_settings_title_usb" msgid="3728686573430917722">"Povezivanje mobitela USB-om"</string>
+ <string name="tether_settings_title_usb" msgid="3728686573430917722">"Dijeljenje internetske veze putem USB-a"</string>
<string name="tether_settings_title_wifi" msgid="4803402057533895526">"Prijenosna pristupna tačka"</string>
- <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Dijeljenje Bluetooth veze"</string>
- <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Povezivanje putem mobitela"</string>
- <string name="tether_settings_title_all" msgid="8910259483383010470">"Povezivanje putem mobitela i prijenosna pristupna tačka"</string>
+ <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Dijeljenje internetske veze putem Bluetootha"</string>
+ <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Dijeljenje internetske veze"</string>
+ <string name="tether_settings_title_all" msgid="8910259483383010470">"Dijeljenje internetske veze i prijenosna pristupna tačka"</string>
<string name="managed_user_title" msgid="449081789742645723">"Sve radne aplikacije"</string>
<string name="unknown" msgid="3544487229740637809">"Nepoznato"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"Korisnik: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
@@ -230,7 +230,7 @@
<string name="development_settings_summary" msgid="8718917813868735095">"Postavi opcije za razvoj aplikacija"</string>
<string name="development_settings_not_available" msgid="355070198089140951">"Opcije za programere nisu dostupne za ovog korisnika"</string>
<string name="vpn_settings_not_available" msgid="2894137119965668920">"VPN postavke nisu dostupne za ovog korisnika"</string>
- <string name="tethering_settings_not_available" msgid="266821736434699780">"Postavke za povezivanje putem mobitela nisu dostupne za ovog korisnika"</string>
+ <string name="tethering_settings_not_available" msgid="266821736434699780">"Postavke dijeljenja internetske veze nisu dostupne za ovog korisnika"</string>
<string name="apn_settings_not_available" msgid="1147111671403342300">"Postavke za ime pristupne tačke nisu dostupne za ovog korisnika"</string>
<string name="enable_adb" msgid="8072776357237289039">"Otklanjanje grešaka putem USB-a"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"Način rada za uklanjanje grešaka kada je povezan USB"</string>
@@ -282,7 +282,7 @@
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Usporavanje skeniranja WiFi-ja"</string>
<string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Nasumičan odabir MAC adrese prema WiFi mreži s prekidima"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Prijenos podataka na mobilnoj mreži uvijek aktivan"</string>
- <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardversko ubrzavanje za povezivanje putem mobitela"</string>
+ <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardversko ubrzavanje dijeljenja internetske veze"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Onemogući apsolutnu jačinu zvuka"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Omogući Gabeldorsche"</string>
@@ -327,7 +327,7 @@
<string name="allow_mock_location_summary" msgid="179780881081354579">"Dozvoli lažne lokacije"</string>
<string name="debug_view_attributes" msgid="3539609843984208216">"Omogući pregled atributa prikaza"</string>
<string name="mobile_data_always_on_summary" msgid="1112156365594371019">"Prijenos podataka na mobilnoj mreži ostaje aktivan čak i kada je aktiviran WiFi (za brzo prebacivanje između mreža)."</string>
- <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Korištenje hardverskog ubrzavanja za povezivanje putem mobitela, ako je dostupno"</string>
+ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Korištenje hardverskog ubrzavanja dijeljenja internetske veze ako je dostupno"</string>
<string name="adb_warning_title" msgid="7708653449506485728">"Omogućiti otklanjanje grešaka putem USB-a?"</string>
<string name="adb_warning_message" msgid="8145270656419669221">"Otklanjanje grešaka putem USB-a je namijenjeno samo u svrhe razvoja aplikacija. Koristite ga za kopiranje podataka između računara i uređaja, instaliranje aplikacija na uređaj bez obavještenja te čitanje podataka iz zapisnika."</string>
<string name="adbwifi_warning_title" msgid="727104571653031865">"Omogućiti bežično otklanjanje grešaka?"</string>
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Kreiranje novog korisnika nije uspjelo"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Kreiranje novog gosta nije uspjelo"</string>
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"Dodavanje korisnika"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Poništi sesiju gosta"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Poništiti sesiju gosta?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Ukloniti gosta?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Poništi"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Poništavanje sesije gosta…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Snimite fotografiju"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberite sliku"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Odabir fotografije"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Previše netočnih pokušaja. S uređaja će se izbrisati podaci."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Previše netočnih pokušaja. Ovaj će se korisnik izbrisati."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Previše netočnih pokušaja. Ovaj će se radni profil izbrisati zajedno sa svim svojim podacima."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Odbaci"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Zadana postavka uređaja"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogućeno"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 1ecf54921498..0c95e18d3c75 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> bateria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> bateria"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Actiu"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Actiu, només l\'esquerre"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Actiu, només el dret"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Actiu, esquerre i dret"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Àudio multimèdia"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Trucades telefòniques"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferència de fitxers"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index eadf71f8cc63..5780f7deef67 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterie"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterie, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterie"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktivní"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktivní, pouze levé"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktivní, pouze pravé"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktivní, levé a pravé"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Zvuk médií"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonní hovory"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Přenos souborů"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index e3cdd5465206..2be9872817c4 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Akkustand: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Akkustand L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>; R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiv, nur links"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiv, nur rechts"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiv, links und rechts"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Medien-Audio"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonanrufe"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Dateiübertragung"</string>
@@ -592,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Nutzer konnte nicht erstellt werden"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Fehler beim Erstellen eines neuen Gasts"</string>
<string name="user_nickname" msgid="262624187455825083">"Alias"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"Nutzer hinzufügen"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gast hinzufügen"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Gast entfernen"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Gast zurücksetzen"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Gast zurücksetzen?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Gast entfernen?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Zurücksetzen"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Gast wird zurückgesetzt…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Foto machen"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Bild auswählen"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Foto auswählen"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Zu viele Fehlversuche. Die Daten auf diesem Gerät werden gelöscht."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Zu viele Fehlversuche. Dieser Nutzer wird gelöscht."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Zu viele Fehlversuche. Dieses Arbeitsprofil und die zugehörigen Daten werden gelöscht."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Schließen"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Gerätestandard"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiviert"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiviert"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index b4fc67c4d89c..d0460487abe7 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> μπαταρία"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Α: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> μπαταρία, Δ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> μπαταρία"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Ενεργό"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Ενεργό, μόνο το αριστερό"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ενεργό, μόνο το δεξί"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ενεργό, αριστερό και δεξί"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Ήχος πολυμέσων"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Τηλεφωνικές κλήσεις"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Μεταφορά αρχείου"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 6c449807a426..59f5b835db64 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Failed to create a new user"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Failed to create a new guest"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"Add user"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Reset guest"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Reset guest?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Remove guest?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Reset"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Resetting guest…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Select photo"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Too many incorrect attempts. This device\'s data will be deleted."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Too many incorrect attempts. This user will be deleted."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Too many incorrect attempts. This work profile and its data will be deleted."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Dismiss"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 00c4def92155..24bd421e3a8f 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Failed to create a new user"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Failed to create a new guest"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"Add user"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Reset guest"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Reset guest?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Remove guest?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Reset"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Resetting guest…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Select photo"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Too many incorrect attempts. This device\'s data will be deleted."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Too many incorrect attempts. This user will be deleted."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Too many incorrect attempts. This work profile and its data will be deleted."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Dismiss"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 6c449807a426..59f5b835db64 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Failed to create a new user"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Failed to create a new guest"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"Add user"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Reset guest"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Reset guest?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Remove guest?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Reset"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Resetting guest…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Select photo"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Too many incorrect attempts. This device\'s data will be deleted."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Too many incorrect attempts. This user will be deleted."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Too many incorrect attempts. This work profile and its data will be deleted."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Dismiss"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 6c449807a426..59f5b835db64 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Failed to create a new user"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Failed to create a new guest"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"Add user"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Reset guest"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Reset guest?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Remove guest?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Reset"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Resetting guest…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Select photo"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Too many incorrect attempts. This device\'s data will be deleted."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Too many incorrect attempts. This user will be deleted."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Too many incorrect attempts. This work profile and its data will be deleted."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Dismiss"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index e6361b3eb16d..3f1cc1991404 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> akut"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> akut, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> akut"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiivne"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiivne, ainult vasak"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiivne, ainult parem"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiivne, vasak ja parem"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Meediaheli"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonikõned"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Failiedastus"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 96fdc15e4d76..3f19420bb27e 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> شارژ باتری"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"چپ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> باتری، راست: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> باتری"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"فعال"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"فعال، فقط چپ"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"فعال، فقط راست"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"فعال، چپ و راست"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"رسانه صوتی"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"تماس‌های تلفنی"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"انتقال فایل"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 61f82029b058..55f9c56371ab 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Akun taso <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"V: akku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, O: akku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiivinen"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiivinen, vain vasen"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiivinen, vain oikea"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiivinen, vasen ja oikea"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Median ääni"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Puhelut"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Tiedostonsiirto"</string>
@@ -198,7 +195,7 @@
<string name="tts_default_lang_summary" msgid="9042620014800063470">"Asettaa puhutulle tekstille kielikohtaisen äänen"</string>
<string name="tts_play_example_title" msgid="1599468547216481684">"Kuuntele esimerkki"</string>
<string name="tts_play_example_summary" msgid="634044730710636383">"Toista lyhyt esittely puhesynteesistä"</string>
- <string name="tts_install_data_title" msgid="1829942496472751703">"Asenna äänitiedot"</string>
+ <string name="tts_install_data_title" msgid="1829942496472751703">"Asenna äänidata"</string>
<string name="tts_install_data_summary" msgid="3608874324992243851">"Asenna puhesynteesiin tarvittavat äänitiedot"</string>
<string name="tts_engine_security_warning" msgid="3372432853837988146">"Tämä puhesynteesimoottori saattaa kerätä kaiken puhutun tekstin, mukaan lukien henkilökohtaiset tiedot kuten salasanat ja luottokorttinumerot. Se on lähtöisin moottorista <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Haluatko ottaa tämän puhesynteesimoottorin käyttöön?"</string>
<string name="tts_engine_network_required" msgid="8722087649733906851">"Tämä kieli vaatii verkkoyhteyden, jotta tekstistä puheeksi muuntaminen toimii."</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 062c58d6370a..0886acacada9 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Pile : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"G : charge à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>; D : charge à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Actif"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Active, gauche seulement"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Active, droite seulement"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Active, gauche et droite"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Paramètres audio du support"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Appels téléphoniques"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transfert de fichier"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 59fea531849f..04db494571fb 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batterie"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"G : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de la batterie, D : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de la batterie"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Actif"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Actif, gauche uniquement"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Actif, droit uniquement"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Actifs, gauche et droit"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Multimédia"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Appels téléphoniques"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transfert de fichiers"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 9c9b23eec642..2f4f1d763fa3 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería. D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Activo"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Activo (só o esquerdo)"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Activo (só o dereito)"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Activos (o esquerdo e o dereito)"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Audio multimedia"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Chamadas telefónicas"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferencia de ficheiros"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index c4179de32c62..5f31d4adeb6c 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> બૅટરી"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> બૅટરી, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> બૅટરી"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"સક્રિય"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"સક્રિય, માત્ર ડાબું"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"સક્રિય, માત્ર જમણું"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"સક્રિય, ડાબું અને જમણું બન્ને"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"મીડિયા ઑડિયો"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"ફોન કૉલ"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ફાઇલ સ્થાનાંતરણ"</string>
@@ -592,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"નવો વપરાશકર્તા બનાવવામાં નિષ્ફળ"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"નવી અતિથિ બનાવવામાં નિષ્ફળ રહ્યાં"</string>
<string name="user_nickname" msgid="262624187455825083">"ઉપનામ"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"વપરાશકર્તા ઉમેરો"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"અતિથિ ઉમેરો"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"અતિથિને કાઢી નાખો"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"અતિથિને રીસેટ કરો"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"અતિથિને રીસેટ કરીએ?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"અતિથિને કાઢી નાખીએ?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"રીસેટ કરો"</string>
<string name="guest_resetting" msgid="7822120170191509566">"અતિથિને રીસેટ કરી રહ્યાં છીએ…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ફોટો લો"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"છબી પસંદ કરો"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ફોટો પસંદ કરો"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"ઘણા બધા ખોટા પ્રયત્નો. આ ડિવાઇસનો ડેટા ડિલીટ કરવામાં આવશે."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"ઘણા બધા ખોટા પ્રયત્નો. આ વપરાશકર્તાને ડિલીટ કરવામાં આવશે."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"ઘણા બધા ખોટા પ્રયત્નો. ઑફિસની આ પ્રોફાઇલ અને તેનો ડેટા ડિલીટ કરવામાં આવશે."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"છોડી દો"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ડિવાઇસ ડિફૉલ્ટ"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"બંધ છે"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ચાલુ છે"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index cceb20406712..214a922bf147 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> बैटरी, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> बैटरी"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"चालू"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"सिर्फ़ बाईं तरफ़ वाला चालू है"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"सिर्फ़ दाईं तरफ़ वाला चालू है"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"बाईं और दाईं तरफ़ वाला चालू है"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"मीडिया ऑडियो"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"फ़ोन कॉल"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"फ़ाइल स्थानांतरण"</string>
@@ -592,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"नया उपयोगकर्ता जोड़ा नहीं जा सका"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"नया मेहमान खाता नहीं बनाया जा सका"</string>
<string name="user_nickname" msgid="262624187455825083">"प्रचलित नाम"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"उपयोगकर्ता जोड़ें"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"मेहमान जोड़ें"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"मेहमान हटाएं"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"मेहमान के तौर पर ब्राउज़ करने का सेशन रीसेट करें"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"क्या आप मेहमान के तौर पर ब्राउज़ करने का सेशन रीसेट करना चाहते हैं?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"क्या मेहमान को हटाना है?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"रीसेट करें"</string>
<string name="guest_resetting" msgid="7822120170191509566">"मेहमान के तौर पर ब्राउज़ करने का सेशन रीसेट किया जा रहा है…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"फ़ोटो खींचें"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"कोई इमेज चुनें"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"फ़ोटो चुनें"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"कई बार गलत कोशिशें की गई हैं. इस डिवाइस का डेटा मिटा दिया जाएगा."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"कई बार गलत कोशिशें की गई हैं. इस उपयोगकर्ता को मिटा दिया जाएगा."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"कई बार गलत कोशिशें की गई हैं. यह वर्क प्रोफ़ाइल और इसका डेटा मिटा दिया जाएगा."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"खारिज करें"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"डिवाइस की डिफ़ॉल्ट सेटिंग"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"बंद है"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"चालू है"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index d072ed4cd636..8ffbd549c446 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Izrada novog korisnika nije uspjela"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Izrada novog gosta nije uspjela"</string>
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"Dodavanje korisnika"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodavanje gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Uklanjanje gosta"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Poništi gostujuću sesiju"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Poništiti gostujuću sesiju?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Ukloniti gosta?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Poništi"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Poništavanje gostujuće sesije…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotografiraj"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Odabir slike"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Previše netočnih pokušaja. S uređaja će se izbrisati podaci."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Previše netočnih pokušaja. Ovaj će se korisnik izbrisati."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Previše netočnih pokušaja. Ovaj će se radni profil izbrisati zajedno sa svim svojim podacima."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Odbaci"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Zadana postavka uređaja"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogućeno"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 2da5d059d035..cd1b9343cdd0 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Մարտկոցի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Ա՝ Մարտկոցի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Ձ՝ Մարտկոցի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Ակտիվ է"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Ակտիվ, միայն ձախ"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ակտիվ, միայն աջ"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ակտիվ, ձախ և աջ"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Մեդիա աուդիո"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Հեռախոսազանգեր"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Ֆայլերի փոխանցում"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 619105ee7baa..ff14ad36056d 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Kr: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterai, Kn: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterai"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktif"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktif, hanya kiri"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktif, hanya kanan"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktif, kiri dan kanan"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Audio media"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Panggilan telepon"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transfer file"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 31c4c6ad51eb..3634d5f63e3e 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> rafhlöðuhleðsla"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> rafhlaða, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> rafhlaða"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Virkt"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Virkt, aðeins vinstra"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Virkt, aðeins hægra"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Virkt, vinstra og hægra"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Hljóð efnis"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Símtöl"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Skráaflutningur"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 09339afad316..af308e41074b 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Batteria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"S: batteria <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: batteria <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Attivo"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Attivo, solo sinistra"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Attivo, solo destra"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Attivo, destra e sinistra"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Audio multimediale"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonate"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Trasferimento file"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 1cf07fad9cb3..c84a3d900992 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"バッテリー <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>、R: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"有効"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"有効、左のみ"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"有効、右のみ"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"有効、左と右"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"メディアの音声"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"電話"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ファイル転送"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index a213788caaa0..8160f70ea994 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Батарея қуаты: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"С: батарея заряды – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, О: батарея заряды – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Қосулы"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Тек сол жағы қосулы"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Тек оң жағы қосулы"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Екеуі де қосулы"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Meдиа аудиосы"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Телефон қоңыраулары"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Файл жіберу"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 4a28d5228776..0208265ade61 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"សកម្ម"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"សកម្មខាងឆ្វេងតែប៉ុណ្ណោះ"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"សកម្មខាងស្ដាំតែប៉ុណ្ណោះ"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"សកម្មខាងឆ្វេង និងស្ដាំ"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"សំឡេង​មេឌៀ"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"ការហៅ​ទូរសព្ទ"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ផ្ទេរ​ឯកសារ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 88c363735dfe..0284bc131b09 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"ಹೊಸ ಅತಿಥಿಯನ್ನು ರಚಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
<string name="user_nickname" msgid="262624187455825083">"ಅಡ್ಡ ಹೆಸರು"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ಅತಿಥಿಯನ್ನು ಸೇರಿಸಿ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"ಅತಿಥಿಯನ್ನು ಮರುಹೊಂದಿಸಿ"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"ಅತಿಥಿ ಬಳಕೆದಾರರನ್ನು ರೀಸೆಟ್ ಮಾಡಬೇಕೆ?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕಬೇಕೇ?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"ರೀಸೆಟ್ ಮಾಡಿ"</string>
<string name="guest_resetting" msgid="7822120170191509566">"ಅತಿಥಿ ಬಳಕೆದಾರರ ಸೆಟ್ಟಿಂಗ್ ಅನ್ನು ರೀಸೆಟ್ ಮಾಡಲಾಗುತ್ತಿದೆ…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ಫೋಟೋ ತೆಗೆದುಕೊಳ್ಳಿ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ಚಿತ್ರವನ್ನು ಆರಿಸಿ"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ಫೋಟೋ ಆಯ್ಕೆಮಾಡಿ"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"ಹಲವಾರು ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಸಾಧನದ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"ಹಲವಾರು ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಬಳಕೆದಾರರನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"ಹಲವಾರು ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್ ಮತ್ತು ಅದರ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"ವಜಾಗೊಳಿಸಿ"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ಸಾಧನದ ಡೀಫಾಲ್ಟ್"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index eaf5ada6c2f1..c16902312712 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"배터리 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"왼쪽: 배터리 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, 오른쪽: 배터리 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"활성"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"활성, 왼쪽만"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"활성, 오른쪽만"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"활성, 왼쪽 및 오른쪽"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"미디어 오디오"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"전화 통화"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"파일 전송"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 3986c4613ae5..af682e0ed331 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ແບັດເຕີຣີ, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ແບັດເຕີຣີ"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ອອນລາຍ"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"ນຳໃຊ້ຢູ່, ຊ້າຍເທົ່ານັ້ນ"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ນຳໃຊ້ຢູ່, ຂວາເທົ່ານັ້ນ"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ນຳໃຊ້ຢູ່, ຊ້າຍ ແລະ ຂວາ"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"ສຽງ"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"ການໂທ"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ການໂອນຍ້າຍໄຟລ໌"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 3993f2bdcd16..b4f2e6ec847f 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Akumuliatoriaus įkrova: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"KAIRĖ: akumuliatoriaus lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, DEŠINĖ: akumuliatoriaus lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktyvus"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktyvus, tik kairysis"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktyvus, tik dešinysis"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktyvus, kairysis ir dešinysis"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Laikmenos garsas"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefono skambučiai"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Failo perkėlimas"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index bc01a6cede50..9153b93c3bc8 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: akumulatora uzlādes līmenis <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: akumulatora uzlādes līmenis <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktīvs"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Ierīce aktīva, tikai kreisā auss"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ierīce aktīva, tikai labā auss"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ierīces aktīvas, kreisā un labā auss"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Multivides audio"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Tālruņa zvani"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Failu pārsūtīšana"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 8cfb4f0336b1..22d724ac869b 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Не успеа да создаде нов корисник"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Не успеа создавањето нов гостин"</string>
<string name="user_nickname" msgid="262624187455825083">"Прекар"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"Додајте корисник"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додајте гостин"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Отстрани гостин"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Ресетирајте го гостинот"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Да се ресетира гостинот?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Да се отстрани гостинот?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Ресетирај"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Се ресетира гостинот…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Фотографирајте"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Одберете слика"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Изберете фотографија"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Премногу неточни обиди. Податоците на уредов ќе се избришат."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Премногу погрешни обиди. Корисников ќе се избрише."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Премногу погрешни обиди. Работниов профил и неговите податоци ќе се избришат."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Отфрли"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Стандардно за уредот"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Оневозможено"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Овозможено"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 0567f7f1768d..b8a0fc845222 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ബാറ്ററി"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"ഇടത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ബാറ്ററി, വലത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ബാറ്ററി"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"സജീവം"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"സജീവമാണ്, ഇടത്തേത് മാത്രം"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"സജീവമാണ്, വലത്തേത് മാത്രം"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"സജീവമാണ്, ഇടത്തേതും വലത്തേതും"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"മീഡിയ ഓഡിയോ"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"ഫോണ്‍‌ കോളുകൾ"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ഫയൽ കൈമാറൽ"</string>
@@ -592,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"പുതിയ ഉപയോക്താവിനെ സൃഷ്‌ടിക്കാനായില്ല"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"പുതിയ അതിഥിയെ സൃഷ്‌ടിക്കാനായില്ല"</string>
<string name="user_nickname" msgid="262624187455825083">"വിളിപ്പേര്"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"ഉപയോക്താവിനെ ചേർക്കുക"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"അതിഥിയെ ചേർക്കുക"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"അതിഥിയെ നീക്കം ചെയ്യുക"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"അതിഥിയെ റീസെറ്റ് ചെയ്യുക"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"അതിഥിയെ റീസെറ്റ് ചെയ്യണോ?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"അതിഥിയെ നീക്കം ചെയ്യണോ?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"റീസെറ്റ് ചെയ്യുക"</string>
<string name="guest_resetting" msgid="7822120170191509566">"അതിഥിയെ റീസെറ്റ് ചെയ്യുന്നു…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ഒരു ഫോട്ടോ എടുക്കുക"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ഒരു ചിത്രം തിരഞ്ഞെടുക്കുക"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ഫോട്ടോ തിരഞ്ഞെടുക്കുക"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"ഒരുപാട് തെറ്റായ ശ്രമങ്ങൾ. ഈ ഉപകരണത്തിലെ ഡാറ്റ ഇല്ലാതാക്കപ്പെടും."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"ഒരുപാട് തെറ്റായ ശ്രമങ്ങൾ. ഈ ഉപയോക്താവ് ഇല്ലാതാക്കപ്പെടും."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"ഒരുപാട് തെറ്റായ ശ്രമങ്ങൾ. ഈ ഔദ്യോഗിക പ്രൊഫൈലും അതിന്റെ ഡാറ്റയും ഇല്ലാതാക്കപ്പെടും."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"ഡിസ്‌മിസ് ചെയ്യുക"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ഉപകരണത്തിന്റെ ഡിഫോൾട്ട് പ്രവർത്തനം"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"പ്രവർത്തനക്ഷമമാക്കി"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 31db20eaa5ce..74556959ef70 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Шинэ хэрэглэгч үүсгэж чадсангүй"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Шинэ зочин үүсгэж чадсангүй"</string>
<string name="user_nickname" msgid="262624187455825083">"Хоч"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"Хэрэглэгч нэмэх"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Зочин нэмэх"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Зочин хасах"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Зочныг шинэчлэх"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Зочныг шинэчлэх үү?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Зочныг хасах уу?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Шинэчлэх"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Зочныг шинэчилж байна…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Зураг авах"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Зураг сонгох"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Зураг сонгох"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Түгжээг хэт олон удаа буруу оруулсан тул энэ төхөөрөмжийн өгөгдлийг устгах болно."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Түгжээг хэт олон удаа буруу оруулсан тул энэ хэрэглэгчийг устгах болно."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Түгжээг хэт олон удаа буруу оруулсан тул энэ ажлын профайл, түүний өгөгдлийн устгах болно."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Хаах"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Төхөөрөмжийн өгөгдмөл"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Идэвхгүй болгосон"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Идэвхжүүлсэн"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index ed658c0f9d5c..49a8c209d854 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Ki: bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Ka: bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktif"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktif, kiri sahaja"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktif, kanan sahaja"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktif, kiri dan kanan"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Audio media"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Panggilan telefon"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Pemindahan fail"</string>
@@ -592,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Gagal membuat pengguna baharu"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Gagal membuat tetamu baharu"</string>
<string name="user_nickname" msgid="262624187455825083">"Nama panggilan"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"Tambah pengguna"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Tambah tetamu"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Alih keluar tetamu"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Tetapkan semula tetamu"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Tetapkan semula tetamu?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Alih keluar tetamu?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Tetapkan semula"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Menetapkan semula tetamu…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ambil foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pilih imej"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Pilih foto"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Terlalu banyak percubaan yang salah. Data peranti ini akan dipadamkan."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Terlalu banyak percubaan yang salah. Pengguna ini akan dipadamkan."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Terlalu banyak percubaan yang salah. Profil kerja ini dan data profil tersebut akan dipadamkan."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Ketepikan"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Lalai peranti"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Dilumpuhkan"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Didayakan"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 7d10f74483ec..010ec69f99b5 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"ဘက်ထရီ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L− ဘက်ထရီ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>၊ R− ဘက်ထရီ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ဖွင့်ထားသည်"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"ဖွင့်ထားသည်၊ ဘယ်သီးသန့်"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ဖွင့်ထားသည်၊ ညာသီးသန့်"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ဖွင့်ထားသည်၊ ဘယ်နှင့် ညာ"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"မီဒီယာ အသံ"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"ဖုန်းခေါ်ဆိုမှုများ"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ဖိုင်လွဲပြောင်းခြင်း"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index bcb67ed703bb..7abf82b357b7 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiv, bare venstre"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiv, bare høyre"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiv, venstre og høyre"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Medielyd"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonsamtaler"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Filoverføring"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index d4cf9bd42acd..53777dfe6cf7 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବ୍ୟାଟେରୀ"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ବ୍ୟାଟେରୀ, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ବ୍ୟାଟେରୀ"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ସକ୍ରିୟ"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"ସକ୍ରିୟ, କେବଳ ବାମ"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ସକ୍ରିୟ, କେବଳ ଡାହାଣ"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ସକ୍ରିୟ, ବାମ ଏବଂ ଡାହାଣ"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"ମିଡିଆ ଅଡିଓ"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"ଫୋନ୍‌ କଲ୍‌‌ଗୁଡ଼ିକ"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ଫାଇଲ୍‌ ଟ୍ରାନ୍ସଫର୍‌"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index ca20485be42b..07ef29c06c52 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ਬੈਟਰੀ"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ਬੈਟਰੀ, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ਬੈਟਰੀ"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ਕਿਰਿਆਸ਼ੀਲ"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"ਕਿਰਿਆਸ਼ੀਲ, ਸਿਰਫ਼ ਖੱਬਾ"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ਕਿਰਿਆਸ਼ੀਲ, ਸਿਰਫ਼ ਸੱਜਾ"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ਕਿਰਿਆਸ਼ੀਲ, ਖੱਬਾ ਅਤੇ ਸੱਜਾ"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"ਮੀਡੀਆ ਆਡੀਓ"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"ਫ਼ੋਨ ਕਾਲਾਂ"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ਫਾਈਲ ਟ੍ਰਾਂਸਫਰ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 57b1aa86580f..b2deca7b9a0a 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> naładowania baterii"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, P: bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Urządzenie aktywne"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktywny, tylko lewa strona"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktywny, tylko prawa strona"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktywny, lewa i prawa strona"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Dźwięk multimediów"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Połączenia telefoniczne"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Przesyłanie pliku"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index cf5ee761771e..73bba6709c63 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Ativo"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Ativo, apenas esquerdo"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ativo, apenas direito"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ativo, esquerdo e direito"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Áudio de multimédia"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Chamadas telefónicas"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferência do ficheiro"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 6d768ae13558..bb9176ec7dc8 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Nu s-a creat noul utilizator"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Nu s-a putut crea un invitat nou"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"Adăugați un utilizator"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adăugați un invitat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ștergeți invitatul"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Resetați sesiunea pentru invitați"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Resetați invitatul?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Excludeți invitatul?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Resetați"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Se resetează invitatul…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Faceți o fotografie"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Alegeți o imagine"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Selectați fotografia"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Prea multe încercări incorecte. Datele de pe acest dispozitiv vor fi șterse."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Prea multe încercări incorecte. Acest utilizator va fi șters."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Prea multe încercări incorecte. Acest profil de serviciu și datele sale vor fi șterse."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Respingeți"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Prestabilit pentru dispozitiv"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Dezactivat"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 6ae0113ac1b4..33f35445ac14 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Уровень заряда: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Л: батарея <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>; П: батарея <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Активно"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Активен, только левое ухо"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Активен, только правое ухо"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Активен, оба уха"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Профиль A2DP"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Звонки"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Профиль OPP"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 8db691f99511..abedbb95de09 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"බැටරිය <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"ව: බැටරිය <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ද: බැටරිය <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ක්‍රියාකාරී"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"සක්‍රිය, වම පමණි"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"සක්‍රිය, දකුණ පමණි"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"සක්‍රිය, වම සහ දකුණ"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"මාධ්‍ය ශ්‍රව්‍ය"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"දුරකථන ඇමතුම්"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ගොනු හුවමාරුව"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index f8d0c063570e..c531a56576c4 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Batéria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Ľ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batérie, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batérie"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktívne"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktívne, iba ľavá strana"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktívne, iba pravá strana"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktívne, ľavá aj pravá strana"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Zvuk médií"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonické hovory"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Prenos súborov"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 9aa6773fc0c7..ad7256d237d2 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: napolnjenost baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: napolnjenost baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktivna"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktivno, samo levo"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktivno, samo desno"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktivno, levo in desno"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Zvok predstavnosti"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonski klici"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Prenos datoteke"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index a0b523dd893f..51fda8cfabb6 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Bateria <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: Bateria <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: Bateria <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktive, vetëm majtas"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktive, vetëm djathtas"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktive, majtas dhe djathtas"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Audioja e klipit \"media\""</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonatat"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferimi i skedarëve"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index e87d3238fd87..80092d0765de 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Ниво батерије је <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Л: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батерије, Д: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батерије"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Активан"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Активно, само с леве стране"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Активно, с десне стране"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Активно, с леве и десне стране"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Звук медија"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Телефонски позиви"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Пренос датотеке"</string>
@@ -592,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Прављење новог корисника није успело"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Прављење новог госта није успело"</string>
<string name="user_nickname" msgid="262624187455825083">"Надимак"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"Додај корисника"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додај госта"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Уклони госта"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Ресетуј сесију госта"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Желите ли да ресетујете сесију госта?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Желите ли да уклоните госта?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Ресетуј"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Сесија госта се ресетује…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Сликај"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Одабери слику"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Изаберите слику"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Превише нетачних покушаја. Избрисаћемо податке са овог уређаја."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Превише нетачних покушаја. Избрисаћемо овог корисника."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Превише нетачних покушаја. Избрисаћемо овај пословни профил и његове податке."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Одбаци"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Подразумевано за уређај"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Онемогућено"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Омогућено"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index f22dbbd106c2..f0400251ca06 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri. H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiv, bara vänster"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiv, bara höger"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiv, vänster och höger"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Medialjud"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonsamtal"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Filöverföring"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 2a9ababeffa6..fcc07c68e715 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Chaji ya betri ni <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ya betri, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ya betri"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Kimeunganishwa"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Inatumika, kushoto pekee"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Inatumika, kulia pekee"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Inatumika, kushoto na kulia"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Sauti ya maudhui"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Simu"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Uhamishaji wa faili"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 58b9bb8f819a..da2527a4b6ab 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"కొత్త యూజర్‌ను క్రియేట్ చేయడం విఫలమైంది"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"కొత్త అతిథిని క్రియేట్ చేయడం విఫలమైంది"</string>
<string name="user_nickname" msgid="262624187455825083">"మారుపేరు"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"యూజర్‌ను జోడించండి"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"గెస్ట్‌ను జోడించండి"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"గెస్ట్‌ను తీసివేయండి"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"గెస్ట్ సెషన్‌ను రీసెట్ చేయండి"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"గెస్ట్ సెషన్‌ను రీసెట్ చేయాలా?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"అతిథిని తీసివేయాలా?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"రీసెట్ చేయండి"</string>
<string name="guest_resetting" msgid="7822120170191509566">"గెస్ట్ సెషన్‌ను రీసెట్ చేస్తోంది…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ఒక ఫోటో తీయండి"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ఇమేజ్‌ను ఎంచుకోండి"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"ఫోటోను ఎంచుకోండి"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"చాలా ఎక్కువ తప్పు ప్రయత్నాలు చేశారు. ఈ పరికరం డేటా తొలగించబడుతుంది."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"చాలా ఎక్కువ తప్పు ప్రయత్నాలు చేశారు. ఈ యూజర్ తొలగించబడతారు."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"చాలా ఎక్కువ తప్పు ప్రయత్నాలు చేశారు. ఈ వర్క్ ప్రొఫైల్, దీని డేటా తొలగించబడతాయి."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"విస్మరించండి"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"పరికర ఆటోమేటిక్ సెట్టింగ్"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"డిజేబుల్ చేయబడింది"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ఎనేబుల్ చేయబడింది"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 89a1dc4b9477..c5bd8268be43 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"สร้างผู้ใช้ใหม่ไม่ได้"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"สร้างผู้เข้าร่วมใหม่ไม่สำเร็จ"</string>
<string name="user_nickname" msgid="262624187455825083">"ชื่อเล่น"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"เพิ่มผู้ใช้"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"เพิ่มผู้ใช้ชั่วคราว"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"นำผู้ใช้ชั่วคราวออก"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"รีเซ็ตผู้เข้าร่วม"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"รีเซ็ตผู้เข้าร่วมไหม"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"นำผู้เข้าร่วมออกไหม"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"รีเซ็ต"</string>
<string name="guest_resetting" msgid="7822120170191509566">"กำลังรีเซ็ตผู้เข้าร่วม…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ถ่ายรูป"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"เลือกรูปภาพ"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"เลือกรูปภาพ"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"ใช้ความพยายามหลายครั้งเกินไป ระบบจะลบข้อมูลในอุปกรณ์เครื่องนี้"</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"ใช้ความพยายามหลายครั้งเกินไป ระบบจะลบผู้ใช้รายนี้"</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"ใช้ความพยายามหลายครั้งเกินไป ระบบจะลบโปรไฟล์งานนี้และข้อมูลในโปรไฟล์"</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"ปิด"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ค่าเริ่มต้นของอุปกรณ์"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ปิดใช้"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"เปิดใช้"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index c704d2e60a83..e08ba325859f 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Hindi nakagawa ng bagong user"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Hindi nakagawa ng bagong guest"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"Magdagdag ng user"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Magdagdag ng bisita"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Alisin ang bisita"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"I-reset ang bisita"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"I-reset ang session ng bisita?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Alisin ang bisita?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"I-reset"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Nire-reset ang bisita…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Kumuha ng larawan"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pumili ng larawan"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Pumili ng larawan"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Masyadong maraming maling pagsubok. Made-delete ang data ng device na ito."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Masyadong maraming maling pagsubok. Made-delete ang user na ito."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Masyadong maraming maling pagsubok. Made-delete ang profile sa trabaho na ito at ang data nito."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"I-dismiss"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Default ng device"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Naka-disable"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Na-enable"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index a0e8948c25eb..c6ea09808db7 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Pil düzeyi <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> pil, Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> pil"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Etkin"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Yalnızca sol tarafta etkin"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Yalnızca sağ tarafta etkin"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Sol ve sağ tarafta etkin"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Medya sesi"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefon aramaları"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Dosya aktarımı"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 7b8d25bbaabd..28ac9fb75ca0 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> заряду акумулятора"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Л: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> заряду акумулятора, П: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> заряду акумулятора"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Активовано"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Активовано, лише лівий"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Активовано, лише правий"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Активовано, лівий і правий"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Звук медіа-файлів"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Телефонні дзвінки"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Передавання файлів"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 7ac80fbdb021..8e2a1a3e7715 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> بیٹری"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"بائيں: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> بیٹری، دائیں: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> بیٹری"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"فعال"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"فعال، صرف بائیں طرف"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"فعال، صرف دائیں طرف"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"فعال، صرف بائیں اور دائیں طرف"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"میڈيا آڈیو"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"فون کالز"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"فائل کی منتقلی"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index e1b4f16e252d..5a9763278cd8 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Faol"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Faol, faqat chap"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Faol, faqat oʻng"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Faol, chap va oʻng"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"A2DP profili"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefon chaqiruvlari"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Fayl uzatish"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 87f796c3ee3c..710a02af7650 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Mức pin <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Trái: Mức pin <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Phải: Mức pin <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Đang hoạt động"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Đang hoạt động, chỉ tai bên trái"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Đang hoạt động, chỉ tai phải"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Đang hoạt động, cả tai phải và tai trái"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Âm thanh nội dung nghe nhìn"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Cuộc gọi điện thoại"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Chuyển tệp"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 1a6167102589..ae579ab03cfb 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> 的电量"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"左:目前电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>;右:目前电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"使用中"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"使用中,仅左耳助听器"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"使用中,仅右耳助听器"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"使用中,左右耳助听器"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"媒体音频"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"通话"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"文件传输"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 24e2666d6a71..0579c3bf385e 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"左:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> 電量,右:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> 電量"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"使用中"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"使用中,僅左耳"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"使用中,僅右耳"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"使用中,左右耳"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"媒體音效"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"通話"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"檔案傳輸"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index e15a6ab5ba77..882190e91123 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -109,12 +109,9 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"左:目前電量為 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>,右:目前電量為 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"使用中"</string>
- <!-- no translation found for bluetooth_hearing_aid_left_active (7084887715570971441) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_right_active (8574683234077567230) -->
- <skip />
- <!-- no translation found for bluetooth_hearing_aid_left_and_right_active (407704460573163973) -->
- <skip />
+ <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"使用中,僅左耳"</string>
+ <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"使用中,僅右耳"</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"使用中,左右耳"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"媒體音訊"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"通話"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"檔案傳輸"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 8468ae50afd8..b24e9349e5c2 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -589,27 +589,21 @@
<string name="add_user_failed" msgid="4809887794313944872">"Yehlulekile ukudala umsebenzisi omusha"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Yehlulekile ukusungula isimenywa esisha"</string>
<string name="user_nickname" msgid="262624187455825083">"Isiteketiso"</string>
- <!-- no translation found for user_add_user (7876449291500212468) -->
- <skip />
+ <string name="user_add_user" msgid="7876449291500212468">"Engeza umsebenzisi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Engeza isivakashi"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Susa isihambeli"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"Setha kabusha isivakashi"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Setha kabusha isimenywa?"</string>
- <!-- no translation found for guest_remove_guest_dialog_title (4548511006624088072) -->
- <skip />
+ <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Susa isihambeli?"</string>
<string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Setha kabusha"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Ukusetha kabusha isimenywa…"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Thatha isithombe"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Khetha isithombe"</string>
<string name="user_image_photo_selector" msgid="433658323306627093">"Khetha isithombe"</string>
- <!-- no translation found for failed_attempts_now_wiping_device (4016329172216428897) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_user (469060411789668050) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_profile (7626589520888963129) -->
- <skip />
- <!-- no translation found for failed_attempts_now_wiping_dialog_dismiss (2749889771223578925) -->
- <skip />
+ <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Imizamo eminingi kakhulu engalungile. Le datha yedivayisi izosulwa."</string>
+ <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Imizamo eminingi kakhulu engalungile. Lo msebenzisi uzosulwa."</string>
+ <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Imizamo eminingi kakhulu engalungile. Le phrofayela yomsebenzi nedatha yayo kuzosulwa."</string>
+ <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Chitha"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Idivayisi ezenzakalelayo"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Ikhutshaziwe"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Inikwe amandla"</string>
diff --git a/packages/SettingsLib/res/values/colors.xml b/packages/SettingsLib/res/values/colors.xml
index 7ab2ed9481b7..d2d747119bba 100644
--- a/packages/SettingsLib/res/values/colors.xml
+++ b/packages/SettingsLib/res/values/colors.xml
@@ -40,4 +40,10 @@
<color name="light_mode_icon_color_single_tone">#ffffff</color>
<color name="user_avatar_color_bg">?android:attr/colorBackgroundFloating</color>
+
+ <!-- QR code scanner colors -->
+ <color name="qr_corner_line_color">#ffdadce0</color>
+ <color name="qr_focused_corner_line_color">#ff1a73e8</color>
+ <color name="qr_background_color">#b3ffffff</color> <!-- 70% white transparency -->
+ <!-- End of QR code scanner colors -->
</resources>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index d893d09a9e3c..8315e8b069c8 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -114,4 +114,10 @@
<fraction name="display_density_max_scale">150%</fraction>
<!-- Minimum density scale. This is available on all devices. -->
<fraction name="display_density_min_scale">85%</fraction>
+
+ <!-- QR code picture size -->
+ <dimen name="qrcode_preview_size">360dp</dimen>
+ <dimen name="qrcode_preview_margin">40dp</dimen>
+ <dimen name="qrcode_preview_radius">30dp</dimen>
+ <dimen name="qrcode_icon_size">27dp</dimen>
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index a9f5f8582403..3a1c107c0ece 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1434,6 +1434,8 @@
<string name="guest_remove_guest_dialog_title">Remove guest?</string>
<!-- Label for button in confirmation dialog when resetting guest user [CHAR LIMIT=35] -->
<string name="guest_reset_guest_confirm_button">Reset</string>
+ <!-- Label for button in confirmation dialog when removing guest session [CHAR LIMIT=35] -->
+ <string name="guest_remove_guest_confirm_button">Remove</string>
<!-- Status message indicating the device is in the process of resetting the guest user. [CHAR_LIMIT=NONE] -->
<string name="guest_resetting">Resetting guest\u2026</string>
<!-- An option in a photo selection dialog to take a new photo [CHAR LIMIT=50] -->
@@ -1580,4 +1582,11 @@
<string name="allow_turn_screen_on">Allow turning the screen on</string>
<!-- Description for a setting which controls whether an app can turn the screen on [CHAR LIMIT=NONE] -->
<string name="allow_turn_screen_on_description">Allow an app to turn the screen on. If granted, the app may turn on the screen at any time without your explicit intent.</string>
+
+ <!-- [CHAR LIMIT=NONE] Le audio QR code scanner title -->
+ <string name="bt_le_audio_scan_qr_code">Scan QR code</string>
+ <!-- [CHAR LIMIT=NONE] Le audio QR code scanner sub-title -->
+ <string name="bt_le_audio_scan_qr_code_scanner">To start listening, center the QR code below</string>
+ <!-- [CHAR LIMIT=NONE] Hint for QR code process failure -->
+ <string name="bt_le_audio_qr_code_is_not_valid_format">QR code isn\u0027t a valid format</string>
</resources>
diff --git a/packages/SettingsLib/res/values/styles.xml b/packages/SettingsLib/res/values/styles.xml
index 015f52cde789..28cd27bf0cad 100644
--- a/packages/SettingsLib/res/values/styles.xml
+++ b/packages/SettingsLib/res/values/styles.xml
@@ -27,4 +27,16 @@
<item name="android:background">@*android:drawable/btn_borderless_rect</item>
<item name="android:gravity">center</item>
</style>
+
+ <style name="TextAppearance.ErrorText"
+ parent="@*android:TextAppearance.DeviceDefault.Body1">
+ <item name="android:textColor">?android:attr/colorError</item>
+ </style>
+
+ <style name="QrCodeScanner">
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:textSize">16sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textDirection">locale</item>
+ </style>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java
index 3ce7a0e4efa5..1f7260972f24 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java
@@ -18,7 +18,32 @@ package com.android.settingslib.bluetooth;
public final class BluetoothBroadcastUtils {
- static final String SCHEME_BT_BROADCAST_METADATA = "BT:";
+ /**
+ * The fragment tag specified to FragmentManager for container activities to manage fragments.
+ */
+ public static final String TAG_FRAGMENT_QR_CODE_SCANNER = "qr_code_scanner_fragment";
+
+ /**
+ * Action for launching qr code scanner activity.
+ */
+ public static final String ACTION_BLUETOOTH_LE_AUDIO_QR_CODE_SCANNER =
+ "android.settings.BLUETOOTH_LE_AUDIO_QR_CODE_SCANNER";
+
+ /**
+ * Extra for {@link android.bluetooth.BluetoothDevice}.
+ */
+ public static final String EXTRA_BLUETOOTH_DEVICE_SINK = "bluetooth_device_sink";
+
+ /**
+ * Extra for checking the {@link android.bluetooth.BluetoothLeBroadcastAssistant} should perform
+ * this operation for all coordinated set members throughout one session or not.
+ */
+ public static final String EXTRA_BLUETOOTH_SINK_IS_GROUP = "bluetooth_sink_is_group";
+
+ /**
+ * Bluetooth scheme.
+ */
+ public static final String SCHEME_BT_BROADCAST_METADATA = "BT:";
// BluetoothLeBroadcastMetadata
static final String PREFIX_BT_ADDRESS_TYPE = "T:";
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
index d904265efda9..60632b677d1b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
@@ -19,7 +19,6 @@ package com.android.settingslib.bluetooth;
import android.annotation.NonNull;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothLeBroadcast;
import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
@@ -71,7 +70,7 @@ public class LocalBluetoothLeBroadcastAssistant implements
}
};
- LocalBluetoothLeBroadcastAssistant(Context context,
+ public LocalBluetoothLeBroadcastAssistant(Context context,
LocalBluetoothProfileManager profileManager) {
mProfileManager = profileManager;
BluetoothAdapter.getDefaultAdapter().
@@ -80,6 +79,40 @@ public class LocalBluetoothLeBroadcastAssistant implements
mBuilder = new BluetoothLeBroadcastMetadata.Builder();
}
+ /**
+ * Add a Broadcast Source to the Broadcast Sink with {@link BluetoothLeBroadcastMetadata}.
+ *
+ * @param sink Broadcast Sink to which the Broadcast Source should be added
+ * @param metadata Broadcast Source metadata to be added to the Broadcast Sink
+ * @param isGroupOp {@code true} if Application wants to perform this operation for all
+ * coordinated set members throughout this session. Otherwise, caller
+ * would have to add, modify, and remove individual set members.
+ */
+ public void addSource(BluetoothDevice sink, BluetoothLeBroadcastMetadata metadata,
+ boolean isGroupOp) {
+ mBluetoothLeBroadcastAssistant.addSource(sink, metadata, isGroupOp);
+ }
+
+ /**
+ * Add a Broadcast Source to the Broadcast Sink with the information which are separated from
+ * the qr code string.
+ *
+ * @param sink Broadcast Sink to which the Broadcast Source should be added
+ * @param sourceAddressType hardware MAC Address of the device. See
+ * {@link BluetoothDevice.AddressType}.
+ * @param presentationDelayMicros presentation delay of this Broadcast Source in microseconds.
+ * @param sourceAdvertisingSid 1-byte long Advertising_SID of the Broadcast Source.
+ * @param broadcastId 3-byte long Broadcast_ID of the Broadcast Source.
+ * @param paSyncInterval Periodic Advertising Sync interval of the broadcast Source,
+ * {@link BluetoothLeBroadcastMetadata#PA_SYNC_INTERVAL_UNKNOWN} if
+ * unknown.
+ * @param isEncrypted whether the Broadcast Source is encrypted.
+ * @param broadcastCode Broadcast Code for this Broadcast Source, null if code is not required.
+ * @param sourceDevice source advertiser address.
+ * @param isGroupOp {@code true} if Application wants to perform this operation for all
+ * coordinated set members throughout this session. Otherwise, caller
+ * would have to add, modify, and remove individual set members.
+ */
public void addSource(@NonNull BluetoothDevice sink, int sourceAddressType,
int presentationDelayMicros, int sourceAdvertisingSid, int broadcastId,
int paSyncInterval, boolean isEncrypted, byte[] broadcastCode,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java
index cf4ba8b46c7a..5b1fefb249a3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java
@@ -83,6 +83,9 @@ public class LocalBluetoothLeBroadcastMetadata {
mSubgroupList = metadata.getSubgroups();
}
+ public LocalBluetoothLeBroadcastMetadata() {
+ }
+
public void setBroadcastCode(byte[] code) {
mBroadcastCode = code;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCamera.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCamera.java
new file mode 100644
index 000000000000..364f46619061
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCamera.java
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.qrcode;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
+import android.hardware.Camera;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.Message;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Size;
+import android.view.Surface;
+import android.view.WindowManager;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.BinaryBitmap;
+import com.google.zxing.DecodeHintType;
+import com.google.zxing.MultiFormatReader;
+import com.google.zxing.ReaderException;
+import com.google.zxing.Result;
+import com.google.zxing.common.HybridBinarizer;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Semaphore;
+
+public class QrCamera extends Handler {
+ private static final String TAG = "QrCamera";
+
+ private static final int MSG_AUTO_FOCUS = 1;
+
+ /**
+ * The max allowed difference between picture size ratio and preview size ratio.
+ * Uses to filter the picture sizes of similar preview size ratio, for example, if a preview
+ * size is 1920x1440, MAX_RATIO_DIFF 0.1 could allow picture size of 720x480 or 352x288 or
+ * 176x44 but not 1920x1080.
+ */
+ private static final double MAX_RATIO_DIFF = 0.1;
+
+ private static final long AUTOFOCUS_INTERVAL_MS = 1500L;
+
+ private static Map<DecodeHintType, List<BarcodeFormat>> HINTS = new ArrayMap<>();
+ private static List<BarcodeFormat> FORMATS = new ArrayList<>();
+
+ static {
+ FORMATS.add(BarcodeFormat.QR_CODE);
+ HINTS.put(DecodeHintType.POSSIBLE_FORMATS, FORMATS);
+ }
+
+ @VisibleForTesting
+ Camera mCamera;
+ private Size mPreviewSize;
+ private WeakReference<Context> mContext;
+ private ScannerCallback mScannerCallback;
+ private MultiFormatReader mReader;
+ private DecodingTask mDecodeTask;
+ private int mCameraOrientation;
+ @VisibleForTesting
+ Camera.Parameters mParameters;
+
+ public QrCamera(Context context, ScannerCallback callback) {
+ mContext = new WeakReference<Context>(context);
+ mScannerCallback = callback;
+ mReader = new MultiFormatReader();
+ mReader.setHints(HINTS);
+ }
+
+ /**
+ * The function start camera preview and capture pictures to decode QR code continuously in a
+ * background task.
+ *
+ * @param surface The surface to be used for live preview.
+ */
+ public void start(SurfaceTexture surface) {
+ if (mDecodeTask == null) {
+ mDecodeTask = new DecodingTask(surface);
+ // Execute in the separate thread pool to prevent block other AsyncTask.
+ mDecodeTask.executeOnExecutor(Executors.newSingleThreadExecutor());
+ }
+ }
+
+ /**
+ * The function stop camera preview and background decode task. Caller call this function when
+ * the surface is being destroyed.
+ */
+ public void stop() {
+ removeMessages(MSG_AUTO_FOCUS);
+ if (mDecodeTask != null) {
+ mDecodeTask.cancel(true);
+ mDecodeTask = null;
+ }
+ if (mCamera != null) {
+ mCamera.stopPreview();
+ releaseCamera();
+ }
+ }
+
+ /** The scanner which includes this QrCodeCamera class should implement this */
+ public interface ScannerCallback {
+
+ /**
+ * The function used to handle the decoding result of the QR code.
+ *
+ * @param result the result QR code after decoding.
+ */
+ void handleSuccessfulResult(String result);
+
+ /** Request the QR code scanner to handle the failure happened. */
+ void handleCameraFailure();
+
+ /**
+ * The function used to get the background View size.
+ *
+ * @return Includes the background view size.
+ */
+ Size getViewSize();
+
+ /**
+ * The function used to get the frame position inside the view
+ *
+ * @param previewSize Is the preview size set by camera
+ * @param cameraOrientation Is the orientation of current Camera
+ * @return The rectangle would like to crop from the camera preview shot.
+ */
+ Rect getFramePosition(Size previewSize, int cameraOrientation);
+
+ /**
+ * Sets the transform to associate with preview area.
+ *
+ * @param transform The transform to apply to the content of preview
+ */
+ void setTransform(Matrix transform);
+
+ /**
+ * Verify QR code is valid or not. The camera will stop scanning if this callback returns
+ * true.
+ *
+ * @param qrCode The result QR code after decoding.
+ * @return Returns true if qrCode hold valid information.
+ */
+ boolean isValid(String qrCode);
+ }
+
+ @VisibleForTesting
+ void setCameraParameter() {
+ mParameters = mCamera.getParameters();
+ mPreviewSize = getBestPreviewSize(mParameters);
+ mParameters.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
+ Size pictureSize = getBestPictureSize(mParameters);
+ mParameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());
+
+ final List<String> supportedFlashModes = mParameters.getSupportedFlashModes();
+ if (supportedFlashModes != null &&
+ supportedFlashModes.contains(Camera.Parameters.FLASH_MODE_OFF)) {
+ mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
+ }
+
+ final List<String> supportedFocusModes = mParameters.getSupportedFocusModes();
+ if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
+ mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
+ } else if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
+ mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
+ }
+ mCamera.setParameters(mParameters);
+ }
+
+ private boolean startPreview() {
+ if (mContext.get() == null) {
+ return false;
+ }
+
+ final WindowManager winManager =
+ (WindowManager) mContext.get().getSystemService(Context.WINDOW_SERVICE);
+ final int rotation = winManager.getDefaultDisplay().getRotation();
+ int degrees = 0;
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ degrees = 0;
+ break;
+ case Surface.ROTATION_90:
+ degrees = 90;
+ break;
+ case Surface.ROTATION_180:
+ degrees = 180;
+ break;
+ case Surface.ROTATION_270:
+ degrees = 270;
+ break;
+ }
+ final int rotateDegrees = (mCameraOrientation - degrees + 360) % 360;
+ mCamera.setDisplayOrientation(rotateDegrees);
+ mCamera.startPreview();
+ if (Camera.Parameters.FOCUS_MODE_AUTO.equals(mParameters.getFocusMode())) {
+ mCamera.autoFocus(/* Camera.AutoFocusCallback */ null);
+ sendMessageDelayed(obtainMessage(MSG_AUTO_FOCUS), AUTOFOCUS_INTERVAL_MS);
+ }
+ return true;
+ }
+
+ private class DecodingTask extends AsyncTask<Void, Void, String> {
+ private QrYuvLuminanceSource mImage;
+ private SurfaceTexture mSurface;
+
+ private DecodingTask(SurfaceTexture surface) {
+ mSurface = surface;
+ }
+
+ @Override
+ protected String doInBackground(Void... tmp) {
+ if (!initCamera(mSurface)) {
+ return null;
+ }
+
+ final Semaphore imageGot = new Semaphore(0);
+ while (true) {
+ // This loop will try to capture preview image continuously until a valid QR Code
+ // decoded. The caller can also call {@link #stop()} to interrupts scanning loop.
+ mCamera.setOneShotPreviewCallback(
+ (imageData, camera) -> {
+ mImage = getFrameImage(imageData);
+ imageGot.release();
+ });
+ try {
+ // Semaphore.acquire() blocking until permit is available, or the thread is
+ // interrupted.
+ imageGot.acquire();
+ Result qrCode = null;
+ try {
+ qrCode =
+ mReader.decodeWithState(
+ new BinaryBitmap(new HybridBinarizer(mImage)));
+ } catch (ReaderException e) {
+ // No logging since every time the reader cannot decode the
+ // image, this ReaderException will be thrown.
+ } finally {
+ mReader.reset();
+ }
+ if (qrCode != null) {
+ if (mScannerCallback.isValid(qrCode.getText())) {
+ return qrCode.getText();
+ }
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return null;
+ }
+ }
+ }
+
+ @Override
+ protected void onPostExecute(String qrCode) {
+ if (qrCode != null) {
+ mScannerCallback.handleSuccessfulResult(qrCode);
+ }
+ }
+
+ private boolean initCamera(SurfaceTexture surface) {
+ final int numberOfCameras = Camera.getNumberOfCameras();
+ Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
+ try {
+ for (int i = 0; i < numberOfCameras; ++i) {
+ Camera.getCameraInfo(i, cameraInfo);
+ if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
+ releaseCamera();
+ mCamera = Camera.open(i);
+ mCameraOrientation = cameraInfo.orientation;
+ break;
+ }
+ }
+ if (mCamera == null && numberOfCameras > 0) {
+ Log.i(TAG, "Can't find back camera. Opening a different camera");
+ Camera.getCameraInfo(0, cameraInfo);
+ releaseCamera();
+ mCamera = Camera.open(0);
+ mCameraOrientation = cameraInfo.orientation;
+ }
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Fail to open camera: " + e);
+ mCamera = null;
+ mScannerCallback.handleCameraFailure();
+ return false;
+ }
+
+ try {
+ if (mCamera == null) {
+ throw new IOException("Cannot find available camera");
+ }
+ mCamera.setPreviewTexture(surface);
+ setCameraParameter();
+ setTransformationMatrix();
+ if (!startPreview()) {
+ throw new IOException("Lost contex");
+ }
+ } catch (IOException ioe) {
+ Log.e(TAG, "Fail to startPreview camera: " + ioe);
+ mCamera = null;
+ mScannerCallback.handleCameraFailure();
+ return false;
+ }
+ return true;
+ }
+ }
+
+ private void releaseCamera() {
+ if (mCamera != null) {
+ mCamera.release();
+ mCamera = null;
+ }
+ }
+
+ /** Set transform matrix to crop and center the preview picture */
+ private void setTransformationMatrix() {
+ final boolean isPortrait = mContext.get().getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_PORTRAIT;
+
+ final int previewWidth = isPortrait ? mPreviewSize.getWidth() : mPreviewSize.getHeight();
+ final int previewHeight = isPortrait ? mPreviewSize.getHeight() : mPreviewSize.getWidth();
+ final float ratioPreview = (float) getRatio(previewWidth, previewHeight);
+
+ // Calculate transformation matrix.
+ float scaleX = 1.0f;
+ float scaleY = 1.0f;
+ if (previewWidth > previewHeight) {
+ scaleY = scaleX / ratioPreview;
+ } else {
+ scaleX = scaleY / ratioPreview;
+ }
+
+ // Set the transform matrix.
+ final Matrix matrix = new Matrix();
+ matrix.setScale(scaleX, scaleY);
+ mScannerCallback.setTransform(matrix);
+ }
+
+ private QrYuvLuminanceSource getFrameImage(byte[] imageData) {
+ final Rect frame = mScannerCallback.getFramePosition(mPreviewSize, mCameraOrientation);
+ final QrYuvLuminanceSource image = new QrYuvLuminanceSource(imageData,
+ mPreviewSize.getWidth(), mPreviewSize.getHeight());
+ return (QrYuvLuminanceSource)
+ image.crop(frame.left, frame.top, frame.width(), frame.height());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_AUTO_FOCUS:
+ // Calling autoFocus(null) will only trigger the camera to focus once. In order
+ // to make the camera continuously auto focus during scanning, need to periodically
+ // trigger it.
+ mCamera.autoFocus(/* Camera.AutoFocusCallback */ null);
+ sendMessageDelayed(obtainMessage(MSG_AUTO_FOCUS), AUTOFOCUS_INTERVAL_MS);
+ break;
+ default:
+ Log.d(TAG, "Unexpected Message: " + msg.what);
+ }
+ }
+
+ /**
+ * Get best preview size from the list of camera supported preview sizes. Compares the
+ * preview size and aspect ratio to choose the best one.
+ */
+ private Size getBestPreviewSize(Camera.Parameters parameters) {
+ final double minRatioDiffPercent = 0.1;
+ final Size windowSize = mScannerCallback.getViewSize();
+ final double winRatio = getRatio(windowSize.getWidth(), windowSize.getHeight());
+ double bestChoiceRatio = 0;
+ Size bestChoice = new Size(0, 0);
+ for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
+ double ratio = getRatio(size.width, size.height);
+ if (size.height * size.width > bestChoice.getWidth() * bestChoice.getHeight()
+ && (Math.abs(bestChoiceRatio - winRatio) / winRatio > minRatioDiffPercent
+ || Math.abs(ratio - winRatio) / winRatio <= minRatioDiffPercent)) {
+ bestChoice = new Size(size.width, size.height);
+ bestChoiceRatio = getRatio(size.width, size.height);
+ }
+ }
+ return bestChoice;
+ }
+
+ /**
+ * Get best picture size from the list of camera supported picture sizes. Compares the
+ * picture size and aspect ratio to choose the best one.
+ */
+ private Size getBestPictureSize(Camera.Parameters parameters) {
+ final Camera.Size previewSize = parameters.getPreviewSize();
+ final double previewRatio = getRatio(previewSize.width, previewSize.height);
+ List<Size> bestChoices = new ArrayList<>();
+ final List<Size> similarChoices = new ArrayList<>();
+
+ // Filter by ratio
+ for (Camera.Size size : parameters.getSupportedPictureSizes()) {
+ double ratio = getRatio(size.width, size.height);
+ if (ratio == previewRatio) {
+ bestChoices.add(new Size(size.width, size.height));
+ } else if (Math.abs(ratio - previewRatio) < MAX_RATIO_DIFF) {
+ similarChoices.add(new Size(size.width, size.height));
+ }
+ }
+
+ if (bestChoices.size() == 0 && similarChoices.size() == 0) {
+ Log.d(TAG, "No proper picture size, return default picture size");
+ Camera.Size defaultPictureSize = parameters.getPictureSize();
+ return new Size(defaultPictureSize.width, defaultPictureSize.height);
+ }
+
+ if (bestChoices.size() == 0) {
+ bestChoices = similarChoices;
+ }
+
+ // Get the best by area
+ int bestAreaDifference = Integer.MAX_VALUE;
+ Size bestChoice = null;
+ final int previewArea = previewSize.width * previewSize.height;
+ for (Size size : bestChoices) {
+ int areaDifference = Math.abs(size.getWidth() * size.getHeight() - previewArea);
+ if (areaDifference < bestAreaDifference) {
+ bestAreaDifference = areaDifference;
+ bestChoice = size;
+ }
+ }
+ return bestChoice;
+ }
+
+ private double getRatio(double x, double y) {
+ return (x < y) ? x / y : y / x;
+ }
+
+ @VisibleForTesting
+ protected void decodeImage(BinaryBitmap image) {
+ Result qrCode = null;
+
+ try {
+ qrCode = mReader.decodeWithState(image);
+ } catch (ReaderException e) {
+ } finally {
+ mReader.reset();
+ }
+
+ if (qrCode != null) {
+ mScannerCallback.handleSuccessfulResult(qrCode.getText());
+ }
+ }
+
+ /**
+ * After {@link #start(SurfaceTexture)}, DecodingTask runs continuously to capture images and
+ * decode QR code. DecodingTask become null After {@link #stop()}.
+ *
+ * Uses this method in test case to prevent power consumption problem.
+ */
+ public boolean isDecodeTaskAlive() {
+ return mDecodeTask != null;
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrDecorateView.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrDecorateView.java
new file mode 100644
index 000000000000..7005d3638f9e
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrDecorateView.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.qrcode;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+
+import com.android.settingslib.R;
+
+public class QrDecorateView extends View {
+ private static final float CORNER_STROKE_WIDTH = 4f; // 4dp
+ private static final float CORNER_LINE_LENGTH = 264f; // 264dp
+ private static final float CORNER_RADIUS = 16f; // 16dp
+
+ final private int mCornerColor;
+ final private int mFocusedCornerColor;
+ final private int mBackgroundColor;
+
+ final private Paint mStrokePaint;
+ final private Paint mTransparentPaint;
+ final private Paint mBackgroundPaint;
+
+ final private float mRadius;
+ final private float mInnerRidus;
+
+ private Bitmap mMaskBitmap;
+ private Canvas mMaskCanvas;
+
+ private RectF mOuterFrame;
+ private RectF mInnerFrame;
+
+ private boolean mFocused;
+
+ public QrDecorateView(Context context) {
+ this(context, null);
+ }
+
+ public QrDecorateView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public QrDecorateView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public QrDecorateView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ mFocused = false;
+ mRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS,
+ getResources().getDisplayMetrics());
+ // Inner radius needs to minus stroke width for keeping the width of border consistent.
+ mInnerRidus = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ CORNER_RADIUS - CORNER_STROKE_WIDTH, getResources().getDisplayMetrics());
+
+ mCornerColor = context.getResources().getColor(R.color.qr_corner_line_color);
+ mFocusedCornerColor = context.getResources().getColor(R.color.qr_focused_corner_line_color);
+ mBackgroundColor = context.getResources().getColor(R.color.qr_background_color);
+
+ mStrokePaint = new Paint();
+ mStrokePaint.setAntiAlias(true);
+
+ mTransparentPaint = new Paint();
+ mTransparentPaint.setAntiAlias(true);
+ mTransparentPaint.setColor(getResources().getColor(android.R.color.transparent));
+ mTransparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+
+ mBackgroundPaint = new Paint();
+ mBackgroundPaint.setColor(mBackgroundColor);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+
+ if(mMaskBitmap == null) {
+ mMaskBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
+ mMaskCanvas = new Canvas(mMaskBitmap);
+ }
+
+ calculateFramePos();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ // Set frame line color.
+ mStrokePaint.setColor(mFocused ? mFocusedCornerColor : mCornerColor);
+ // Draw background color.
+ mMaskCanvas.drawColor(mBackgroundColor);
+ // Draw outer corner.
+ mMaskCanvas.drawRoundRect(mOuterFrame, mRadius, mRadius, mStrokePaint);
+ // Draw inner transparent corner.
+ mMaskCanvas.drawRoundRect(mInnerFrame, mInnerRidus, mInnerRidus, mTransparentPaint);
+
+ canvas.drawBitmap(mMaskBitmap, 0, 0, mBackgroundPaint);
+ super.onDraw(canvas);
+ }
+
+ private void calculateFramePos() {
+ final int centralX = getWidth() / 2;
+ final int centralY = getHeight() / 2;
+ final float cornerLineLength = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ CORNER_LINE_LENGTH, getResources().getDisplayMetrics()) / 2;
+ final float strokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ CORNER_STROKE_WIDTH, getResources().getDisplayMetrics());
+
+ mOuterFrame = new RectF(centralX - cornerLineLength, centralY - cornerLineLength,
+ centralX + cornerLineLength, centralY + cornerLineLength);
+ mInnerFrame = new RectF(mOuterFrame.left + strokeWidth, mOuterFrame.top + strokeWidth,
+ mOuterFrame.right - strokeWidth, mOuterFrame.bottom - strokeWidth);
+ }
+
+ // Draws green lines if focused. Otherwise, draws white lines.
+ public void setFocused(boolean focused) {
+ mFocused = focused;
+ invalidate();
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrYuvLuminanceSource.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrYuvLuminanceSource.java
new file mode 100644
index 000000000000..421cf5c40b69
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrYuvLuminanceSource.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.qrcode;
+
+import com.google.zxing.LuminanceSource;
+
+public class QrYuvLuminanceSource extends LuminanceSource {
+
+ private byte[] mYuvData;
+ private int mWidth;
+ private int mHeight;
+
+ public QrYuvLuminanceSource(byte[] yuvData, int width, int height) {
+ super(width, height);
+
+ mWidth = width;
+ mHeight = height;
+ mYuvData = yuvData;
+ }
+
+ @Override
+ public boolean isCropSupported() {
+ return true;
+ }
+
+ @Override
+ public LuminanceSource crop(int left, int top, int crop_width, int crop_height) {
+ final byte[] newImage = new byte[crop_width * crop_height];
+ int inputOffset = top * mWidth + left;
+
+ if (left + crop_width > mWidth || top + crop_height > mHeight) {
+ throw new IllegalArgumentException("cropped rectangle does not fit within image data.");
+ }
+
+ for (int y = 0; y < crop_height; y++) {
+ System.arraycopy(mYuvData, inputOffset, newImage, y * crop_width, crop_width);
+ inputOffset += mWidth;
+ }
+ return new QrYuvLuminanceSource(newImage, crop_width, crop_height);
+ }
+
+ @Override
+ public byte[] getRow(int y, byte[] row) {
+ if (y < 0 || y >= mHeight) {
+ throw new IllegalArgumentException("Requested row is outside the image: " + y);
+ }
+ if (row == null || row.length < mWidth) {
+ row = new byte[mWidth];
+ }
+ System.arraycopy(mYuvData, y * mWidth, row, 0, mWidth);
+ return row;
+ }
+
+ @Override
+ public byte[] getMatrix() {
+ return mYuvData;
+ }
+}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 03384a231e2e..a10ca9e75355 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -495,6 +495,9 @@
<!-- Permission needed for CTS test - DefaultDisplayModeTest -->
<uses-permission android:name="android.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE" />
+ <!-- Permissions needed for manual testing telephony time zone detector behavior -->
+ <uses-permission android:name="android.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE" />
+
<!-- Permissions needed for CTS test - TimeManagerTest -->
<uses-permission android:name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION" />
<uses-permission android:name="android.permission.SUGGEST_EXTERNAL_TIME" />
@@ -671,9 +674,15 @@
<!-- Permission required for CTS test - CtsTelephonyTestCases -->
<uses-permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE" />
+ <!-- Permission required for CTS test - CtsPersistentDataBlockManagerTestCases -->
+ <uses-permission android:name="android.permission.ACCESS_PDB_STATE" />
+
<!-- Permission required for CTS test - CtsAppEnumerationTestCases -->
<uses-permission android:name="android.permission.MAKE_UID_VISIBLE" />
+ <!-- Permission required for CTS test - CtsKeystoreTestCases -->
+ <uses-permission android:name="android.permission.REQUEST_UNIQUE_ID_ATTESTATION" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
index c480197d23dc..d15b8c169535 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
@@ -24,59 +24,19 @@ import android.util.IntProperty
import android.view.View
import android.view.ViewGroup
import android.view.animation.Interpolator
+import kotlin.math.max
+import kotlin.math.min
/**
* A class that allows changes in bounds within a view hierarchy to animate seamlessly between the
* start and end state.
*/
class ViewHierarchyAnimator {
- // TODO(b/221418522): make this private once it can't be passed as an arg anymore.
- enum class Bound(val label: String, val overrideTag: Int) {
- LEFT("left", R.id.tag_override_left) {
- override fun setValue(view: View, value: Int) {
- view.left = value
- }
-
- override fun getValue(view: View): Int {
- return view.left
- }
- },
- TOP("top", R.id.tag_override_top) {
- override fun setValue(view: View, value: Int) {
- view.top = value
- }
-
- override fun getValue(view: View): Int {
- return view.top
- }
- },
- RIGHT("right", R.id.tag_override_right) {
- override fun setValue(view: View, value: Int) {
- view.right = value
- }
-
- override fun getValue(view: View): Int {
- return view.right
- }
- },
- BOTTOM("bottom", R.id.tag_override_bottom) {
- override fun setValue(view: View, value: Int) {
- view.bottom = value
- }
-
- override fun getValue(view: View): Int {
- return view.bottom
- }
- };
-
- abstract fun setValue(view: View, value: Int)
- abstract fun getValue(view: View): Int
- }
-
companion object {
/** Default values for the animation. These can all be overridden at call time. */
private const val DEFAULT_DURATION = 500L
- private val DEFAULT_INTERPOLATOR = Interpolators.EMPHASIZED
+ private val DEFAULT_INTERPOLATOR = Interpolators.STANDARD
+ private val DEFAULT_ADDITION_INTERPOLATOR = Interpolators.STANDARD_DECELERATE
private val DEFAULT_BOUNDS = setOf(Bound.LEFT, Bound.TOP, Bound.RIGHT, Bound.BOTTOM)
/** The properties used to animate the view bounds. */
@@ -112,6 +72,9 @@ class ViewHierarchyAnimator {
* Successive calls to this method override the previous settings ([interpolator] and
* [duration]). The changes take effect on the next animation.
*
+ * Returns true if the [rootView] is already visible and will be animated, false otherwise.
+ * To animate the addition of a view, see [animateAddition].
+ *
* TODO(b/221418522): remove the ability to select which bounds to animate and always
* animate all of them.
*/
@@ -121,8 +84,8 @@ class ViewHierarchyAnimator {
bounds: Set<Bound> = DEFAULT_BOUNDS,
interpolator: Interpolator = DEFAULT_INTERPOLATOR,
duration: Long = DEFAULT_DURATION
- ) {
- animate(rootView, bounds, interpolator, duration, false /* ephemeral */)
+ ): Boolean {
+ return animate(rootView, bounds, interpolator, duration, ephemeral = false)
}
/**
@@ -138,8 +101,8 @@ class ViewHierarchyAnimator {
bounds: Set<Bound> = DEFAULT_BOUNDS,
interpolator: Interpolator = DEFAULT_INTERPOLATOR,
duration: Long = DEFAULT_DURATION
- ) {
- animate(rootView, bounds, interpolator, duration, true /* ephemeral */)
+ ): Boolean {
+ return animate(rootView, bounds, interpolator, duration, ephemeral = true)
}
private fun animate(
@@ -148,9 +111,42 @@ class ViewHierarchyAnimator {
interpolator: Interpolator,
duration: Long,
ephemeral: Boolean
- ) {
- val listener = createListener(bounds, interpolator, duration, ephemeral)
+ ): Boolean {
+ if (!isVisible(
+ rootView.visibility,
+ rootView.left,
+ rootView.top,
+ rootView.right,
+ rootView.bottom
+ )
+ ) {
+ return false
+ }
+
+ val listener = createUpdateListener(bounds, interpolator, duration, ephemeral)
recursivelyAddListener(rootView, listener)
+ return true
+ }
+
+ /**
+ * Returns a new [View.OnLayoutChangeListener] that when called triggers a layout animation
+ * for the specified [bounds], using [interpolator] and [duration].
+ *
+ * If [ephemeral] is true, the listener is unregistered after the first animation. Otherwise
+ * it keeps listening for further updates.
+ */
+ private fun createUpdateListener(
+ bounds: Set<Bound>,
+ interpolator: Interpolator,
+ duration: Long,
+ ephemeral: Boolean
+ ): View.OnLayoutChangeListener {
+ return createListener(
+ bounds,
+ interpolator,
+ duration,
+ ephemeral
+ )
}
/**
@@ -173,11 +169,87 @@ class ViewHierarchyAnimator {
}
}
+ /**
+ * Instruct the animator to watch for changes to the layout of [rootView] and its children,
+ * and animate the next time the hierarchy appears after not being visible. It uses the
+ * given [interpolator] and [duration].
+ *
+ * The start state of the animation is controlled by [origin]. This value can be any of the
+ * four corners, any of the four edges, or the center of the view. If any margins are added
+ * on the side(s) of the origin, the translation of those margins can be included by
+ * specifying [includeMargins].
+ *
+ * Returns true if the [rootView] is invisible and will be animated, false otherwise. To
+ * animate an already visible view, see [animate] and [animateNextUpdate].
+ *
+ * Then animator unregisters itself once the first addition animation is complete.
+ */
+ @JvmOverloads
+ fun animateAddition(
+ rootView: View,
+ origin: Hotspot = Hotspot.CENTER,
+ interpolator: Interpolator = DEFAULT_ADDITION_INTERPOLATOR,
+ duration: Long = DEFAULT_DURATION,
+ includeMargins: Boolean = false
+ ): Boolean {
+ if (isVisible(
+ rootView.visibility,
+ rootView.left,
+ rootView.top,
+ rootView.right,
+ rootView.bottom
+ )
+ ) {
+ return false
+ }
+
+ val listener = createAdditionListener(
+ origin, interpolator, duration, ignorePreviousValues = !includeMargins
+ )
+ recursivelyAddListener(rootView, listener)
+ return true
+ }
+
+ /**
+ * Returns a new [View.OnLayoutChangeListener] that on the next call triggers a layout
+ * addition animation from the given [origin], using [interpolator] and [duration].
+ *
+ * If [ignorePreviousValues] is true, the animation will only span the area covered by the
+ * new bounds. Otherwise it will include the margins between the previous and new bounds.
+ */
+ private fun createAdditionListener(
+ origin: Hotspot,
+ interpolator: Interpolator,
+ duration: Long,
+ ignorePreviousValues: Boolean
+ ): View.OnLayoutChangeListener {
+ return createListener(
+ DEFAULT_BOUNDS,
+ interpolator,
+ duration,
+ ephemeral = true,
+ origin = origin,
+ ignorePreviousValues = ignorePreviousValues
+ )
+ }
+
+ /**
+ * Returns a new [View.OnLayoutChangeListener] that when called triggers a layout animation
+ * for the specified [bounds], using [interpolator] and [duration].
+ *
+ * If [ephemeral] is true, the listener is unregistered after the first animation. Otherwise
+ * it keeps listening for further updates.
+ *
+ * [origin] specifies whether the start values should be determined by a hotspot, and
+ * [ignorePreviousValues] controls whether the previous values should be taken into account.
+ */
private fun createListener(
bounds: Set<Bound>,
interpolator: Interpolator,
duration: Long,
- ephemeral: Boolean
+ ephemeral: Boolean,
+ origin: Hotspot? = null,
+ ignorePreviousValues: Boolean = false
): View.OnLayoutChangeListener {
return object : View.OnLayoutChangeListener {
override fun onLayoutChange(
@@ -186,21 +258,21 @@ class ViewHierarchyAnimator {
top: Int,
right: Int,
bottom: Int,
- oldLeft: Int,
- oldTop: Int,
- oldRight: Int,
- oldBottom: Int
+ previousLeft: Int,
+ previousTop: Int,
+ previousRight: Int,
+ previousBottom: Int
) {
if (view == null) return
- val startLeft = getBound(view, Bound.LEFT) ?: oldLeft
- val startTop = getBound(view, Bound.TOP) ?: oldTop
- val startRight = getBound(view, Bound.RIGHT) ?: oldRight
- val startBottom = getBound(view, Bound.BOTTOM) ?: oldBottom
+ val startLeft = getBound(view, Bound.LEFT) ?: previousLeft
+ val startTop = getBound(view, Bound.TOP) ?: previousTop
+ val startRight = getBound(view, Bound.RIGHT) ?: previousRight
+ val startBottom = getBound(view, Bound.BOTTOM) ?: previousBottom
(view.getTag(R.id.tag_animator) as? ObjectAnimator)?.cancel()
- if (view.visibility == View.GONE || view.visibility == View.INVISIBLE) {
+ if (!isVisible(view.visibility, left, top, right, bottom)) {
setBound(view, Bound.LEFT, left)
setBound(view, Bound.TOP, top)
setBound(view, Bound.RIGHT, right)
@@ -208,11 +280,17 @@ class ViewHierarchyAnimator {
return
}
- val startValues = mapOf(
- Bound.LEFT to startLeft,
- Bound.TOP to startTop,
- Bound.RIGHT to startRight,
- Bound.BOTTOM to startBottom
+ val startValues = processStartValues(
+ origin,
+ left,
+ top,
+ right,
+ bottom,
+ startLeft,
+ startTop,
+ startRight,
+ startBottom,
+ ignorePreviousValues
)
val endValues = mapOf(
Bound.LEFT to left,
@@ -221,11 +299,12 @@ class ViewHierarchyAnimator {
Bound.BOTTOM to bottom
)
- val boundsToAnimate = bounds.toMutableSet()
- if (left == startLeft) boundsToAnimate.remove(Bound.LEFT)
- if (top == startTop) boundsToAnimate.remove(Bound.TOP)
- if (right == startRight) boundsToAnimate.remove(Bound.RIGHT)
- if (bottom == startBottom) boundsToAnimate.remove(Bound.BOTTOM)
+ val boundsToAnimate = mutableSetOf<Bound>()
+ bounds.forEach { bound ->
+ if (endValues.getValue(bound) != startValues.getValue(bound)) {
+ boundsToAnimate.add(bound)
+ }
+ }
if (boundsToAnimate.isNotEmpty()) {
startAnimation(
@@ -242,11 +321,136 @@ class ViewHierarchyAnimator {
}
}
+ /**
+ * Returns whether the given [visibility] and bounds are consistent with a view being
+ * currently visible on screen.
+ */
+ private fun isVisible(
+ visibility: Int,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int
+ ): Boolean {
+ return visibility == View.VISIBLE && left != right && top != bottom
+ }
+
+ /**
+ * Compute the actual starting values based on the requested [origin] and on
+ * [ignorePreviousValues].
+ *
+ * If [origin] is null, the resolved start values will be the same as those passed in, or
+ * the same as the new values if [ignorePreviousValues] is true. If [origin] is not null,
+ * the start values are resolved based on it, and [ignorePreviousValues] controls whether or
+ * not newly introduced margins are included.
+ *
+ * Base case
+ * 1) origin=TOP
+ * x---------x x---------x x---------x x---------x x---------x
+ * x---------x | | | | | |
+ * -> -> x---------x -> | | -> | |
+ * x---------x | |
+ * x---------x
+ * 2) origin=BOTTOM_LEFT
+ * x---------x
+ * x-------x | |
+ * -> -> x----x -> | | -> | |
+ * x--x | | | | | |
+ * x x--x x----x x-------x x---------x
+ * 3) origin=CENTER
+ * x---------x
+ * x-----x x-------x | |
+ * x -> x---x -> | | -> | | -> | |
+ * x-----x x-------x | |
+ * x---------x
+ *
+ * In case the start and end values differ in the direction of the origin, and
+ * [ignorePreviousValues] is false, the previous values are used and a translation is
+ * included in addition to the view expansion.
+ *
+ * origin=TOP_LEFT - (0,0,0,0) -> (30,30,70,70)
+ * x
+ * x--x
+ * x--x x----x
+ * -> -> | | -> x------x
+ * x----x | |
+ * | |
+ * x------x
+ */
+ private fun processStartValues(
+ origin: Hotspot?,
+ newLeft: Int,
+ newTop: Int,
+ newRight: Int,
+ newBottom: Int,
+ previousLeft: Int,
+ previousTop: Int,
+ previousRight: Int,
+ previousBottom: Int,
+ ignorePreviousValues: Boolean
+ ): Map<Bound, Int> {
+ val startLeft = if (ignorePreviousValues) newLeft else previousLeft
+ val startTop = if (ignorePreviousValues) newTop else previousTop
+ val startRight = if (ignorePreviousValues) newRight else previousRight
+ val startBottom = if (ignorePreviousValues) newBottom else previousBottom
+
+ var left = startLeft
+ var top = startTop
+ var right = startRight
+ var bottom = startBottom
+
+ if (origin != null) {
+ left = when (origin) {
+ Hotspot.CENTER -> (newLeft + newRight) / 2
+ Hotspot.BOTTOM_LEFT, Hotspot.LEFT, Hotspot.TOP_LEFT -> min(startLeft, newLeft)
+ Hotspot.TOP, Hotspot.BOTTOM -> newLeft
+ Hotspot.TOP_RIGHT, Hotspot.RIGHT, Hotspot.BOTTOM_RIGHT -> max(
+ startRight,
+ newRight
+ )
+ }
+ top = when (origin) {
+ Hotspot.CENTER -> (newTop + newBottom) / 2
+ Hotspot.TOP_LEFT, Hotspot.TOP, Hotspot.TOP_RIGHT -> min(startTop, newTop)
+ Hotspot.LEFT, Hotspot.RIGHT -> newTop
+ Hotspot.BOTTOM_RIGHT, Hotspot.BOTTOM, Hotspot.BOTTOM_LEFT -> max(
+ startBottom,
+ newBottom
+ )
+ }
+ right = when (origin) {
+ Hotspot.CENTER -> (newLeft + newRight) / 2
+ Hotspot.TOP_RIGHT, Hotspot.RIGHT, Hotspot.BOTTOM_RIGHT -> max(
+ startRight,
+ newRight
+ )
+ Hotspot.TOP, Hotspot.BOTTOM -> newRight
+ Hotspot.BOTTOM_LEFT, Hotspot.LEFT, Hotspot.TOP_LEFT -> min(startLeft, newLeft)
+ }
+ bottom = when (origin) {
+ Hotspot.CENTER -> (newTop + newBottom) / 2
+ Hotspot.BOTTOM_RIGHT, Hotspot.BOTTOM, Hotspot.BOTTOM_LEFT -> max(
+ startBottom,
+ newBottom
+ )
+ Hotspot.LEFT, Hotspot.RIGHT -> newBottom
+ Hotspot.TOP_LEFT, Hotspot.TOP, Hotspot.TOP_RIGHT -> min(startTop, newTop)
+ }
+ }
+
+ return mapOf(
+ Bound.LEFT to left,
+ Bound.TOP to top,
+ Bound.RIGHT to right,
+ Bound.BOTTOM to bottom
+ )
+ }
+
private fun recursivelyAddListener(view: View, listener: View.OnLayoutChangeListener) {
// Make sure that only one listener is active at a time.
- val oldListener = view.getTag(R.id.tag_layout_listener)
- if (oldListener != null && oldListener is View.OnLayoutChangeListener) {
- view.removeOnLayoutChangeListener(oldListener)
+ val previousListener = view.getTag(R.id.tag_layout_listener)
+ if (previousListener != null && previousListener is View.OnLayoutChangeListener) {
+ view.removeOnLayoutChangeListener(previousListener)
}
view.addOnLayoutChangeListener(listener)
@@ -268,9 +472,12 @@ class ViewHierarchyAnimator {
}
/**
- * Initiates the animation of a single bound by creating the animator, registering it with
- * the [view], and starting it. If [ephemeral], the layout change listener is unregistered
- * at the end of the animation, so no more animations happen.
+ * Initiates the animation of the requested [bounds] between [startValues] and [endValues]
+ * by creating the animator, registering it with the [view], and starting it using
+ * [interpolator] and [duration].
+ *
+ * If [ephemeral] is true, the layout change listener is unregistered at the end of the
+ * animation, so no more animations happen.
*/
private fun startAnimation(
view: View,
@@ -325,4 +532,52 @@ class ViewHierarchyAnimator {
animator.start()
}
}
+
+ /** An enum used to determine the origin of addition animations. */
+ enum class Hotspot {
+ CENTER, LEFT, TOP_LEFT, TOP, TOP_RIGHT, RIGHT, BOTTOM_RIGHT, BOTTOM, BOTTOM_LEFT
+ }
+
+ // TODO(b/221418522): make this private once it can't be passed as an arg anymore.
+ enum class Bound(val label: String, val overrideTag: Int) {
+ LEFT("left", R.id.tag_override_left) {
+ override fun setValue(view: View, value: Int) {
+ view.left = value
+ }
+
+ override fun getValue(view: View): Int {
+ return view.left
+ }
+ },
+ TOP("top", R.id.tag_override_top) {
+ override fun setValue(view: View, value: Int) {
+ view.top = value
+ }
+
+ override fun getValue(view: View): Int {
+ return view.top
+ }
+ },
+ RIGHT("right", R.id.tag_override_right) {
+ override fun setValue(view: View, value: Int) {
+ view.right = value
+ }
+
+ override fun getValue(view: View): Int {
+ return view.right
+ }
+ },
+ BOTTOM("bottom", R.id.tag_override_bottom) {
+ override fun setValue(view: View, value: Int) {
+ view.bottom = value
+ }
+
+ override fun getValue(view: View): Int {
+ return view.bottom
+ }
+ };
+
+ abstract fun setValue(view: View, value: Int)
+ abstract fun getValue(view: View): Int
+ }
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewRootSync.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewRootSync.kt
index 35b4166675ed..76de7b503451 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewRootSync.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewRootSync.kt
@@ -1,14 +1,11 @@
package com.android.systemui.animation
-import android.app.ActivityManager
import android.view.View
import android.window.SurfaceSyncer
/** A util class to synchronize 2 view roots. */
// TODO(b/200284684): Remove this class.
object ViewRootSync {
- // TODO(b/217621394): Remove special handling for low-RAM devices after animation sync is fixed
- private val forceDisableSynchronization = ActivityManager.isLowRamDeviceStatic()
private var surfaceSyncer: SurfaceSyncer? = null
/**
@@ -23,8 +20,7 @@ object ViewRootSync {
otherView: View,
then: () -> Unit
) {
- if (forceDisableSynchronization ||
- !view.isAttachedToWindow || view.viewRootImpl == null ||
+ if (!view.isAttachedToWindow || view.viewRootImpl == null ||
!otherView.isAttachedToWindow || otherView.viewRootImpl == null ||
view.viewRootImpl == otherView.viewRootImpl) {
// No need to synchronize if either the touch surface or dialog view is not attached
diff --git a/packages/SystemUI/res/drawable/ic_broadcast_code_eye.xml b/packages/SystemUI/res/drawable/ic_broadcast_code_eye.xml
new file mode 100644
index 000000000000..dc50a5dcab07
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_broadcast_code_eye.xml
@@ -0,0 +1,26 @@
+<!--
+Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,16Q13.875,16 15.188,14.688Q16.5,13.375 16.5,11.5Q16.5,9.625 15.188,8.312Q13.875,7 12,7Q10.125,7 8.812,8.312Q7.5,9.625 7.5,11.5Q7.5,13.375 8.812,14.688Q10.125,16 12,16ZM12,14.2Q10.875,14.2 10.088,13.412Q9.3,12.625 9.3,11.5Q9.3,10.375 10.088,9.587Q10.875,8.8 12,8.8Q13.125,8.8 13.913,9.587Q14.7,10.375 14.7,11.5Q14.7,12.625 13.913,13.412Q13.125,14.2 12,14.2ZM12,19Q8.35,19 5.35,16.962Q2.35,14.925 1,11.5Q2.35,8.075 5.35,6.037Q8.35,4 12,4Q15.65,4 18.65,6.037Q21.65,8.075 23,11.5Q21.65,14.925 18.65,16.962Q15.65,19 12,19ZM12,11.5Q12,11.5 12,11.5Q12,11.5 12,11.5Q12,11.5 12,11.5Q12,11.5 12,11.5Q12,11.5 12,11.5Q12,11.5 12,11.5Q12,11.5 12,11.5Q12,11.5 12,11.5ZM12,17Q14.825,17 17.188,15.512Q19.55,14.025 20.8,11.5Q19.55,8.975 17.188,7.487Q14.825,6 12,6Q9.175,6 6.812,7.487Q4.45,8.975 3.2,11.5Q4.45,14.025 6.812,15.512Q9.175,17 12,17Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_mic_off.xml b/packages/SystemUI/res/drawable/ic_mic_off.xml
new file mode 100644
index 000000000000..fe23754f7467
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_mic_off.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v5.17l1.82,1.82c0.11,-0.31 0.18,-0.64 0.18,-0.99V5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v1.17l2,2V5zM2.81,2.81L1.39,4.22l11.65,11.65c-0.33,0.08 -0.68,0.13 -1.04,0.13 -2.76,0 -5,-2.24 -5,-5H5c0,3.53 2.61,6.43 6,6.92V21h2v-3.08c0.57,-0.08 1.12,-0.24 1.64,-0.46l5.14,5.14 1.41,-1.41L2.81,2.81zM19,11h-2c0,0.91 -0.26,1.75 -0.69,2.48l1.46,1.46C18.54,13.82 19,12.47 19,11z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_videocam_off.xml b/packages/SystemUI/res/drawable/ic_videocam_off.xml
new file mode 100644
index 000000000000..b609f36d912d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_videocam_off.xml
@@ -0,0 +1,13 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,8v2.67l5.85,5.85C20.94,16.37 21,16.2 21,16V8c0,-0.82 -0.94,-1.29 -1.6,-0.8L17,9V8c0,-1.1 -0.9,-2 -2,-2h-4.67l2,2H15z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M2,3.32l2.71,2.71C3.74,6.17 3,7 3,8v8c0,1.1 0.9,2 2,2h11.68l3,3l1.41,-1.41L3.41,1.91L2,3.32zM5,8h1.68l8,8H5V8z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml b/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml
index cb63300f819b..3f56bafef134 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml
@@ -17,13 +17,8 @@
<TextClock
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/date_view"
+ style="@style/clock_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingHorizontal="@dimen/dream_overlay_complication_shadow_padding"
- android:gravity="center_horizontal"
- android:textColor="@android:color/white"
- android:shadowColor="@color/keyguard_shadow_color"
- android:shadowRadius="?attr/shadowRadius"
android:format12Hour="EEE, MMM d"
- android:format24Hour="EEE, MMM d"
- android:textSize="@dimen/dream_overlay_complication_clock_date_text_size"/>
+ android:format24Hour="EEE, MMM d"/>
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml b/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml
index 76fe58c29852..f05922fb395c 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml
@@ -17,10 +17,6 @@
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/weather_view"
+ style="@style/clock_subtitle"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingHorizontal="@dimen/dream_overlay_complication_shadow_padding"
- android:textColor="@android:color/white"
- android:shadowColor="@color/keyguard_shadow_color"
- android:shadowRadius="?attr/shadowRadius"
- android:textSize="@dimen/dream_overlay_complication_weather_text_size"/>
+ android:layout_height="wrap_content" />
diff --git a/packages/SystemUI/res/layout/media_output_broadcast_area.xml b/packages/SystemUI/res/layout/media_output_broadcast_area.xml
new file mode 100644
index 000000000000..4e33e123f12a
--- /dev/null
+++ b/packages/SystemUI/res/layout/media_output_broadcast_area.xml
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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:id="@+id/broadcast_info_area"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="start|center_vertical"
+ android:orientation="vertical">
+
+ <View
+ style="@style/BroadcastDialog.Divider.Horizontal"
+ android:layout_marginBottom="6dp"/>
+
+ <LinearLayout
+ android:id="@+id/broadcast_qrcode_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <ImageView
+ android:id="@+id/qrcode_view"
+ android:layout_width="@dimen/media_output_qrcode_size"
+ android:layout_height="@dimen/media_output_qrcode_size"
+ android:src="@android:color/transparent"
+ android:gravity="start|center_vertical"
+ android:layout_marginStart="82dp"/>
+ <ImageView
+ android:id="@+id/broadcast_info"
+ android:layout_width="@dimen/media_output_broadcast_info"
+ android:layout_height="@dimen/media_output_broadcast_info"
+ android:src="@drawable/ic_info_outline"
+ android:tint="?android:attr/textColorTertiary"
+ android:clickable="true"
+ android:layout_marginTop="168dp"
+ android:layout_marginStart="31dp"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/broadcast_name_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/media_output_broadcast_info_item_padding_start"
+ android:paddingEnd="@dimen/media_output_broadcast_info_item_padding_end"
+ android:orientation="horizontal">
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ style="@style/BroadcastDialog.InfoItem" >
+ <TextView
+ android:id="@+id/broadcast_name_title"
+ android:text="@string/media_output_broadcast_name"
+ style="@style/BroadcastDialog.InfoItem.Title" />
+ <TextView
+ android:id="@+id/broadcast_name_summary"
+ style="@style/BroadcastDialog.InfoItem.Summary" />
+ </LinearLayout>
+
+ <View
+ style="@style/BroadcastDialog.Divider.Vertical" />
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|center_vertical">
+ <ImageView
+ android:id="@+id/broadcast_name_edit"
+ style="@style/BroadcastDialog.InfoItem.Edit" />
+ </FrameLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/broadcast_code_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/media_output_broadcast_info_item_padding_start"
+ android:paddingEnd="@dimen/media_output_broadcast_info_item_padding_end"
+ android:orientation="horizontal" >
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ style="@style/BroadcastDialog.InfoItem" >
+ <TextView
+ android:id="@+id/broadcast_code_title"
+ android:text="@string/media_output_broadcast_code"
+ style="@style/BroadcastDialog.InfoItem.Title" />
+ <TextView
+ android:id="@+id/broadcast_code_summary"
+ style="@style/BroadcastDialog.InfoItem.Summary" />
+ </LinearLayout>
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|center_vertical"
+ android:layout_marginEnd="26dp">
+ <ImageView
+ android:id="@+id/broadcast_code_eye"
+ android:layout_width="20dp"
+ android:layout_height="16dp"
+ android:background="?android:attr/selectableItemBackground"
+ android:clickable="true"
+ android:focusable="true"
+ android:src="@drawable/ic_broadcast_code_eye"
+ android:tint="?android:attr/textColorPrimary"/>
+ </FrameLayout>
+
+ <View
+ style="@style/BroadcastDialog.Divider.Vertical" />
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|center_vertical">
+ <ImageView
+ android:id="@+id/broadcast_code_edit"
+ style="@style/BroadcastDialog.InfoItem.Edit" />
+ </FrameLayout>
+ </LinearLayout>
+
+ <View
+ style="@style/BroadcastDialog.Divider.Horizontal"
+ android:layout_marginTop="14dp"
+ android:layout_marginBottom="20dp"/>
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_output_broadcast_update_dialog.xml b/packages/SystemUI/res/layout/media_output_broadcast_update_dialog.xml
new file mode 100644
index 000000000000..8b7a019b791b
--- /dev/null
+++ b/packages/SystemUI/res/layout/media_output_broadcast_update_dialog.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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="wrap_content"
+ android:paddingLeft="?android:attr/dialogPreferredPadding"
+ android:paddingRight="?android:attr/dialogPreferredPadding">
+ <EditText
+ android:id="@+id/broadcast_edit_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="48dp"
+ android:textAlignment="viewStart"/>
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index 05343e75b448..836f59dc8fb2 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -71,6 +71,13 @@
</LinearLayout>
</LinearLayout>
+ <ViewStub
+ android:id="@+id/broadcast_qrcode"
+ android:layout="@layout/media_output_broadcast_area"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+ </ViewStub>
+
<LinearLayout
android:id="@+id/device_list"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index a9e6d22461b6..94f6c3952e06 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -42,4 +42,8 @@
<!-- Whether to use window background blur for the volume dialog. -->
<bool name="config_volumeDialogUseBackgroundBlur">true</bool>
+
+ <!-- Whether to tint the icon of the sensor hardware privacy toggle unblock dialog.
+ Set to false if using a custom icon. -->
+ <bool name="config_unblockHwSensorIconEnableTint">true</bool>
</resources>
diff --git a/packages/SystemUI/res/values-television/dimens.xml b/packages/SystemUI/res/values-television/dimens.xml
index d4bfc4d11b89..7845ac49c06d 100644
--- a/packages/SystemUI/res/values-television/dimens.xml
+++ b/packages/SystemUI/res/values-television/dimens.xml
@@ -57,4 +57,7 @@
<dimen name="privacy_chip_dot_bg_height">18dp</dimen>
<dimen name="privacy_chip_dot_bg_radius">9dp</dimen>
+ <dimen name="unblock_hw_sensor_icon_width">@dimen/bottom_sheet_icon_size</dimen>
+ <dimen name="unblock_hw_sensor_icon_height">@dimen/bottom_sheet_icon_size</dimen>
+
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c3e933d2dd43..7702724cec16 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1382,8 +1382,7 @@
<!-- Dream overlay complications related dimensions -->
<dimen name="dream_overlay_complication_clock_time_text_size">72sp</dimen>
- <dimen name="dream_overlay_complication_clock_date_text_size">18sp</dimen>
- <dimen name="dream_overlay_complication_weather_text_size">18sp</dimen>
+ <dimen name="dream_overlay_complication_clock_subtitle_text_size">18sp</dimen>
<dimen name="dream_overlay_complication_preview_text_size">36sp</dimen>
<dimen name="dream_overlay_complication_preview_icon_padding">28dp</dimen>
<dimen name="dream_overlay_complication_shadow_padding">2dp</dimen>
@@ -1431,4 +1430,15 @@
<dimen name="dream_overlay_complication_margin">0dp</dimen>
<dimen name="status_view_margin_horizontal">0dp</dimen>
+
+ <!-- Media output broadcast dialog QR code picture size -->
+ <dimen name="media_output_qrcode_size">216dp</dimen>
+ <dimen name="media_output_broadcast_info">21dp</dimen>
+ <dimen name="media_output_broadcast_info_item_width">256dp</dimen>
+ <dimen name="media_output_broadcast_info_item_height">56dp</dimen>
+ <dimen name="media_output_broadcast_info_item_padding_start">43dp</dimen>
+ <dimen name="media_output_broadcast_info_item_padding_end">31dp</dimen>
+ <dimen name="media_output_broadcast_info_title_height">24dp</dimen>
+ <dimen name="media_output_broadcast_info_summary_height">20dp</dimen>
+ <dimen name="media_output_broadcast_info_edit">18dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/drawables.xml b/packages/SystemUI/res/values/drawables.xml
new file mode 100644
index 000000000000..a1d6baa4808e
--- /dev/null
+++ b/packages/SystemUI/res/values/drawables.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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>
+ <!-- Drawable shown for the sensor unblock dialog when blocked by the hardware camera toggle -->
+ <drawable name="unblock_hw_sensor_camera">@drawable/ic_videocam_off</drawable>
+ <!-- Drawable shown for the sensor unblock dialog when blocked by the hardware microphone toggle -->
+ <drawable name="unblock_hw_sensor_microphone">@drawable/ic_mic_off</drawable>
+ <!-- Drawable shown for the sensor unblock dialog when blocked by the hardware privacy toggle -->
+ <drawable name="unblock_hw_sensor_all">@drawable/ic_videocam_off</drawable>
+ <!-- Second drawable shown for the sensor unblock dialog when blocked by the hardware privacy toggle -->
+ <drawable name="unblock_hw_sensor_all_second">@drawable/ic_mic_off</drawable>
+</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e00c7bd398be..898f66d9939b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -338,7 +338,7 @@
<!-- Message shown when a biometric is authenticated, waiting for the user to confirm authentication [CHAR LIMIT=40]-->
<string name="biometric_dialog_tap_confirm">Tap Confirm to complete</string>
<!-- Message shown when a biometric has authenticated with a user's face and is waiting for the user to confirm authentication [CHAR LIMIT=60]-->
- <string name="biometric_dialog_tap_confirm_with_face">Unlocked by your face. Press to continue.</string>
+ <string name="biometric_dialog_tap_confirm_with_face">Unlocked by face. Press to continue.</string>
<!-- Talkback string when a biometric is authenticated [CHAR LIMIT=NONE] -->
<string name="biometric_dialog_authenticated">Authenticated</string>
@@ -720,16 +720,52 @@
<string name="sensor_privacy_start_use_mic_dialog_title">Unblock device microphone?</string>
<!--- Title of dialog triggered if the camera is disabled but an app tried to access it. [CHAR LIMIT=150] -->
<string name="sensor_privacy_start_use_camera_dialog_title">Unblock device camera?</string>
- <!--- Title of dialog triggered if the camera is disabled but an app tried to access it. [CHAR LIMIT=150] -->
+ <!--- Title of dialog triggered if both microphone and camera are disabled but an app tried to access them. [CHAR LIMIT=150] -->
<string name="sensor_privacy_start_use_mic_camera_dialog_title">Unblock device camera and microphone?</string>
<!--- Content of dialog triggered if the microphone is disabled but an app tried to access it. [CHAR LIMIT=NONE] -->
<string name="sensor_privacy_start_use_mic_dialog_content">This unblocks access for all apps and services allowed to use your microphone.</string>
<!--- Content of dialog triggered if the camera is disabled but an app tried to access it. [CHAR LIMIT=NONE] -->
<string name="sensor_privacy_start_use_camera_dialog_content">This unblocks access for all apps and services allowed to use your camera.</string>
- <!--- Content of dialog triggered if the camera is disabled but an app tried to access it. [CHAR LIMIT=NONE] -->
+ <!--- Title of dialog triggered if both microphone and camera are disabled but an app tried to access them. [CHAR LIMIT=150] -->
<string name="sensor_privacy_start_use_mic_camera_dialog_content">This unblocks access for all apps and services allowed to use your camera or microphone.</string>
+ <!--- Title of dialog triggered if the microphone is blocked by a hardware privacy switch but an app tried to access it. [CHAR LIMIT=150] -->
+ <string name="sensor_privacy_start_use_mic_blocked_dialog_title">Microphone is blocked</string>
+ <!--- Title of dialog triggered if the camera is blocked by a hardware privacy switch but an app tried to access it. [CHAR LIMIT=150] -->
+ <string name="sensor_privacy_start_use_camera_blocked_dialog_title">Camera is blocked</string>
+ <!--- Title of dialog triggered if both microphone and camera are blocked by a hardware privacy switch but an app tried to access them. [CHAR LIMIT=150] -->
+ <string name="sensor_privacy_start_use_mic_camera_blocked_dialog_title">The mic &amp; camera are blocked</string>
+
+ <!--- Content of dialog triggered if the microphone is disabled by HW toggle but an app tried to access it. [CHAR LIMIT=NONE] -->
+ <string name="sensor_privacy_start_use_mic_blocked_dialog_content">
+ To unblock, move the privacy switch on your device to the microphone on position to allow
+ microphone access. Refer to the device manual to locate the privacy switch on your device.
+ </string>
+ <!--- Content of dialog triggered if the camera is disabled by HW toggle but an app tried to access it. [CHAR LIMIT=NONE] -->
+ <string name="sensor_privacy_start_use_camera_blocked_dialog_content">
+ To unblock, move the privacy switch on your device to the camera on position to allow camera
+ access. Refer to the device manual to locate the privacy switch on your device.
+ </string>
+ <!--- Content of dialog triggered if the camera is disabled by HW toggle but an app tried to access it. [CHAR LIMIT=NONE] -->
+ <string name="sensor_privacy_start_use_mic_camera_blocked_dialog_content">
+ To unblock them, move the privacy switch on your device to the unblocked position to allow
+ access. Refer to the device manual to locate the privacy switch on your device.
+ </string>
+
+ <!--- Content of toast triggered if the microphone privacy is unblocked while the HW toggle privacy dialog was shown. [CHAR LIMIT=NONE] -->
+ <string name="sensor_privacy_mic_unblocked_toast_content">
+ Microphone available
+ </string>
+ <!--- Content of toast triggered if the camera privacy is unblocked while the HW toggle privacy dialog was shown. [CHAR LIMIT=NONE] -->
+ <string name="sensor_privacy_camera_unblocked_toast_content">
+ Camera available
+ </string>
+ <!--- Content of toast triggered if both mic and camera privacy is unblocked while the HW toggle privacy dialog was shown. [CHAR LIMIT=NONE] -->
+ <string name="sensor_privacy_mic_camera_unblocked_toast_content">
+ Microphone and camera available
+ </string>
+
<!-- Default name for the media device shown in the output switcher when the name is not available [CHAR LIMIT=30] -->
<string name="media_seamless_other_device">Other device</string>
@@ -837,9 +873,6 @@
<!-- Message of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
<string name="guest_exit_guest_dialog_message">All apps and data in this session will be deleted.</string>
- <!-- Label for button in confirmation dialog when exiting guest session [CHAR LIMIT=35] -->
- <string name="guest_exit_guest_dialog_remove">Remove</string>
-
<!-- Title of the notification when resuming an existing guest session [CHAR LIMIT=NONE] -->
<string name="guest_wipe_session_title">Welcome back, guest!</string>
@@ -2227,6 +2260,21 @@
<!-- Button text for stopping casting [CHAR LIMIT=60] -->
<string name="media_output_dialog_button_stop_casting">Stop casting</string>
+ <!-- Media Output Broadcast Dialog -->
+ <!-- Title for Broadcast First Notify Dialog [CHAR LIMIT=60] -->
+ <string name="media_output_first_broadcast_title">How broadcasting works</string>
+ <!-- Title for Broadcast Notify Dialog [CHAR LIMIT=60] -->
+ <string name="media_output_broadcast">Broadcast</string>
+ <!-- Message for notifying the user about the Broadcast at first launch [CHAR LIMIT=NONE] -->
+ <string name="media_output_first_notify_broadcast_message">People near you with compatible Bluetooth devices can listen to the media you\'re broadcasting</string>
+ <!-- Message for Broadcasting information and QR code [CHAR LIMIT=NONE] -->
+ <string name="media_output_broadcasting_message">To listen to your broadcast, people nearby with compatible Bluetooth devices can scan your QR code or use your broadcast name and password</string>
+ <!-- Title for Broadcast Name [CHAR LIMIT=60] -->
+ <string name="media_output_broadcast_name">Broadcast Name</string>
+ <!-- Title for Broadcast Code(Password) [CHAR LIMIT=60] -->
+ <string name="media_output_broadcast_code">Password</string>
+ <!-- Button for change broadcast name and broadcast code [CHAR LIMIT=60] -->
+ <string name="media_output_broadcast_dialog_save">Save</string>
<!-- Label for clip data when copying the build number off QS [CHAR LIMIT=NONE]-->
<string name="build_number_clip_data_label">Build number</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 7de0f653cc10..847aefdd67ce 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -1071,4 +1071,80 @@
<item name="android:fontFamily">?android:attr/textAppearanceSmall</item>
<item name="android:textDirection">locale</item>
</style>
+
+ <style name="BroadcastDialog">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">start|center_vertical</item>
+ </style>
+
+ <style name="BroadcastDialog.InfoItem">
+ <item name="android:layout_width">@dimen/media_output_broadcast_info_item_width</item>
+ <item name="android:layout_height">@dimen/media_output_broadcast_info_item_height</item>
+ <item name="android:clickable">false</item>
+ <item name="android:gravity">start|center_vertical</item>
+ </style>
+
+ <style name="BroadcastDialog.InfoItem.Title">
+ <item name="android:layout_height">@dimen/media_output_broadcast_info_title_height</item>
+ <item name="android:textAppearance">@style/TextAppearance.BroadcastDialog</item>
+ </style>
+
+ <style name="BroadcastDialog.InfoItem.Summary">
+ <item name="android:layout_height">@dimen/media_output_broadcast_info_summary_height</item>
+ <item name="android:textAppearance">@style/TextAppearance.BroadcastDialog.Secondary</item>
+ </style>
+
+ <style name="BroadcastDialog.InfoItem.Edit">
+ <item name="android:layout_width">@dimen/media_output_broadcast_info_edit</item>
+ <item name="android:layout_height">@dimen/media_output_broadcast_info_edit</item>
+ <item name="android:background">?android:attr/selectableItemBackground</item>
+ <item name="android:clickable">true</item>
+ <item name="android:focusable">true</item>
+ <item name="android:src">@*android:drawable/ic_mode_edit</item>
+ <item name="android:tint">?android:attr/textColorPrimary</item>
+ </style>
+
+ <style name="BroadcastDialog.Divider">
+ <item name="android:background">?android:attr/textColorSecondary</item>
+ </style>
+
+ <style name="BroadcastDialog.Divider.Horizontal">
+ <item name="android:layout_width">348dp</item>
+ <item name="android:layout_height">1dp</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ </style>
+
+
+ <style name="BroadcastDialog.Divider.Vertical">
+ <item name="android:layout_width">1dp</item>
+ <item name="android:layout_height">28dp</item>
+ <item name="android:layout_marginEnd">30dp</item>
+ </style>
+
+ <style name="TextAppearance.BroadcastDialog">
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:textSize">16sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textDirection">locale</item>
+ </style>
+
+ <style name="TextAppearance.BroadcastDialog.Secondary">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+
+ <!-- Dream Overlay Complication UI styles -->
+ <style name="clock_subtitle">
+ <item name="android:textSize">@dimen/dream_overlay_complication_clock_subtitle_text_size
+ </item>
+ <item name="android:paddingHorizontal">@dimen/dream_overlay_complication_shadow_padding
+ </item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:textColor">@android:color/white</item>
+ <item name="android:gravity">center_horizontal</item>
+ <item name="android:ellipsize">none</item>
+ <item name="android:shadowColor">@color/keyguard_shadow_color</item>
+ <item name="android:shadowRadius">?attr/shadowRadius</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
index 567e7aa3d78f..238690cd48e2 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
@@ -30,14 +30,16 @@ import android.window.PictureInPictureSurfaceTransaction;
*/
public class PipSurfaceTransactionHelper {
private final int mCornerRadius;
+ private final int mShadowRadius;
private final Matrix mTmpTransform = new Matrix();
private final float[] mTmpFloat9 = new float[9];
private final RectF mTmpSourceRectF = new RectF();
private final RectF mTmpDestinationRectF = new RectF();
private final Rect mTmpDestinationRect = new Rect();
- public PipSurfaceTransactionHelper(int cornerRadius) {
+ public PipSurfaceTransactionHelper(int cornerRadius, int shadowRadius) {
mCornerRadius = cornerRadius;
+ mShadowRadius = shadowRadius;
}
public PictureInPictureSurfaceTransaction scale(
@@ -52,9 +54,10 @@ public class PipSurfaceTransactionHelper {
final float cornerRadius = getScaledCornerRadius(sourceBounds, destinationBounds);
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setPosition(leash, positionX, positionY)
- .setCornerRadius(leash, cornerRadius);
+ .setCornerRadius(leash, cornerRadius)
+ .setShadowRadius(leash, mShadowRadius);
return newPipSurfaceTransaction(positionX, positionY,
- mTmpFloat9, 0 /* rotation */, cornerRadius, sourceBounds);
+ mTmpFloat9, 0 /* rotation */, cornerRadius, mShadowRadius, sourceBounds);
}
public PictureInPictureSurfaceTransaction scale(
@@ -69,9 +72,10 @@ public class PipSurfaceTransactionHelper {
final float cornerRadius = getScaledCornerRadius(sourceBounds, destinationBounds);
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setPosition(leash, positionX, positionY)
- .setCornerRadius(leash, cornerRadius);
+ .setCornerRadius(leash, cornerRadius)
+ .setShadowRadius(leash, mShadowRadius);
return newPipSurfaceTransaction(positionX, positionY,
- mTmpFloat9, degree, cornerRadius, sourceBounds);
+ mTmpFloat9, degree, cornerRadius, mShadowRadius, sourceBounds);
}
public PictureInPictureSurfaceTransaction scaleAndCrop(
@@ -92,9 +96,10 @@ public class PipSurfaceTransactionHelper {
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setWindowCrop(leash, mTmpDestinationRect)
.setPosition(leash, left, top)
- .setCornerRadius(leash, cornerRadius);
+ .setCornerRadius(leash, cornerRadius)
+ .setShadowRadius(leash, mShadowRadius);
return newPipSurfaceTransaction(left, top,
- mTmpFloat9, 0 /* rotation */, cornerRadius, mTmpDestinationRect);
+ mTmpFloat9, 0 /* rotation */, cornerRadius, mShadowRadius, mTmpDestinationRect);
}
public PictureInPictureSurfaceTransaction scaleAndRotate(
@@ -124,9 +129,10 @@ public class PipSurfaceTransactionHelper {
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setWindowCrop(leash, mTmpDestinationRect)
.setPosition(leash, adjustedPositionX, adjustedPositionY)
- .setCornerRadius(leash, cornerRadius);
+ .setCornerRadius(leash, cornerRadius)
+ .setShadowRadius(leash, mShadowRadius);
return newPipSurfaceTransaction(adjustedPositionX, adjustedPositionY,
- mTmpFloat9, degree, cornerRadius, mTmpDestinationRect);
+ mTmpFloat9, degree, cornerRadius, mShadowRadius, mTmpDestinationRect);
}
/** @return the round corner radius scaled by given from and to bounds */
@@ -137,12 +143,13 @@ public class PipSurfaceTransactionHelper {
}
private static PictureInPictureSurfaceTransaction newPipSurfaceTransaction(
- float posX, float posY, float[] float9, float rotation, float cornerRadius,
- Rect windowCrop) {
+ float posX, float posY, float[] float9, float rotation,
+ float cornerRadius, float shadowRadius, Rect windowCrop) {
return new PictureInPictureSurfaceTransaction.Builder()
.setPosition(posX, posY)
.setTransform(float9, rotation)
.setCornerRadius(cornerRadius)
+ .setShadowRadius(shadowRadius)
.setWindowCrop(windowCrop)
.build();
}
@@ -150,7 +157,7 @@ public class PipSurfaceTransactionHelper {
/** @return {@link SurfaceControl.Transaction} instance with vsync-id */
public static SurfaceControl.Transaction newSurfaceControlTransaction() {
final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
- tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
+ tx.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
return tx;
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 4894c498ec58..120b09a2ad31 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -47,6 +47,7 @@ import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
import android.window.PictureInPictureSurfaceTransaction;
import android.window.RemoteTransition;
+import android.window.TaskSnapshot;
import android.window.TransitionFilter;
import android.window.TransitionInfo;
import android.window.WindowContainerToken;
@@ -322,7 +323,16 @@ public class RemoteTransitionCompat implements Parcelable {
}
@Override public ThumbnailData screenshotTask(int taskId) {
- return mWrapped != null ? mWrapped.screenshotTask(taskId) : null;
+ try {
+ final TaskSnapshot snapshot =
+ ActivityTaskManager.getService().takeTaskSnapshot(taskId);
+ if (snapshot != null) {
+ return new ThumbnailData(snapshot);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to screenshot task", e);
+ }
+ return null;
}
@Override public void setInputConsumerEnabled(boolean enabled) {
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
index 157191302010..3c4c1b6dc2d1 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
@@ -23,7 +23,9 @@ import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Color;
import android.icu.text.NumberFormat;
+import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.settingslib.Utils;
@@ -34,6 +36,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.ViewController;
+import java.io.PrintWriter;
import java.util.Locale;
import java.util.Objects;
import java.util.TimeZone;
@@ -43,6 +46,7 @@ import java.util.TimeZone;
* {@link KeyguardClockSwitchController}.
*/
public class AnimatableClockController extends ViewController<AnimatableClockView> {
+ private static final String TAG = "AnimatableClockCtrl";
private static final int FORMAT_NUMBER = 1234567890;
private final StatusBarStateController mStatusBarStateController;
@@ -140,6 +144,7 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie
@Override
protected void onViewAttached() {
+ Log.d(TAG, "onViewAttached mView=" + mView);
updateLocale();
mBroadcastDispatcher.registerReceiver(mLocaleBroadcastReceiver,
new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
@@ -157,12 +162,25 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie
@Override
protected void onViewDetached() {
+ Log.d(TAG, "onViewDetached mView=" + mView);
mBroadcastDispatcher.unregisterReceiver(mLocaleBroadcastReceiver);
mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
mBatteryController.removeCallback(mBatteryCallback);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
}
+ /**
+ * @return the number of pixels below the baseline. For fonts that support languages such as
+ * Burmese, this space can be significant.
+ */
+ public float getBottom() {
+ if (mView.getPaint() != null && mView.getPaint().getFontMetrics() != null) {
+ return mView.getPaint().getFontMetrics().bottom;
+ }
+
+ return 0f;
+ }
+
/** Animate the clock appearance */
public void animateAppear() {
if (!mIsDozing) mView.animateAppearOnLockscreen();
@@ -223,4 +241,12 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie
mView.setColors(mDozingColor, mLockScreenColor);
mView.animateDoze(mIsDozing, false);
}
+
+ /**
+ * Dump information for debugging
+ */
+ public void dump(@NonNull PrintWriter pw) {
+ pw.println(this);
+ mView.dump(pw);
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.kt b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.kt
index 357be2503a3a..ad8c126aa2fa 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.kt
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.kt
@@ -24,10 +24,12 @@ import android.content.Context
import android.graphics.Canvas
import android.text.format.DateFormat
import android.util.AttributeSet
+import android.util.Log
import android.widget.TextView
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
+import java.io.PrintWriter
import java.util.Calendar
import java.util.Locale
import java.util.TimeZone
@@ -42,6 +44,9 @@ class AnimatableClockView @JvmOverloads constructor(
defStyleAttr: Int = 0,
defStyleRes: Int = 0
) : TextView(context, attrs, defStyleAttr, defStyleRes) {
+ private val tag = "AnimatableClockView"
+
+ private var lastMeasureCall: CharSequence = ""
private val time = Calendar.getInstance()
@@ -122,6 +127,11 @@ class AnimatableClockView @JvmOverloads constructor(
time.timeInMillis = System.currentTimeMillis()
text = DateFormat.format(format, time)
contentDescription = DateFormat.format(descFormat, time)
+ Log.d(tag, "refreshTime this=$this" +
+ " currTimeContextDesc=$contentDescription" +
+ " measuredHeight=$measuredHeight" +
+ " lastMeasureCall=$lastMeasureCall" +
+ " isSingleLineInternal=$isSingleLineInternal")
}
fun onTimeZoneChanged(timeZone: TimeZone?) {
@@ -132,6 +142,7 @@ class AnimatableClockView @JvmOverloads constructor(
@SuppressLint("DrawAllocation")
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ lastMeasureCall = DateFormat.format(descFormat, System.currentTimeMillis())
val animator = textAnimator
if (animator == null) {
textAnimator = TextAnimator(layout) { invalidate() }
@@ -140,9 +151,20 @@ class AnimatableClockView @JvmOverloads constructor(
} else {
animator.updateLayout(layout)
}
+ Log.v(tag, "onMeasure this=$this" +
+ " currTimeContextDesc=$contentDescription" +
+ " heightMeasureSpecMode=${MeasureSpec.getMode(heightMeasureSpec)}" +
+ " heightMeasureSpecSize=${MeasureSpec.getSize(heightMeasureSpec)}" +
+ " measuredWidth=$measuredWidth" +
+ " measuredHeight=$measuredHeight" +
+ " isSingleLineInternal=$isSingleLineInternal")
}
override fun onDraw(canvas: Canvas) {
+ // intentionally doesn't call super.onDraw here or else the text will be rendered twice
+ Log.d(tag, "onDraw this=$this" +
+ " currTimeContextDesc=$contentDescription" +
+ " isSingleLineInternal=$isSingleLineInternal")
textAnimator?.draw(canvas)
}
@@ -329,6 +351,17 @@ class AnimatableClockView @JvmOverloads constructor(
refreshTime()
}
+ fun dump(pw: PrintWriter) {
+ pw.println("$this")
+ pw.println(" measuredWidth=$measuredWidth")
+ pw.println(" measuredHeight=$measuredHeight")
+ pw.println(" singleLineInternal=$isSingleLineInternal")
+ pw.println(" lastMeasureCall=$lastMeasureCall")
+ pw.println(" currText=$text")
+ pw.println(" currTimeContextDesc=$contentDescription")
+ pw.println(" time=$time")
+ }
+
// DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often.
// This is an optimization to ensure we only recompute the patterns when the inputs change.
private object Patterns {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 8eb528980a96..fcac6813ae7a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -33,12 +33,16 @@ import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
+import androidx.annotation.NonNull;
+
import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.clock.ClockManager;
+import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -46,13 +50,14 @@ import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.settings.SecureSettings;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
@@ -64,7 +69,8 @@ import javax.inject.Inject;
/**
* Injectable controller for {@link KeyguardClockSwitch}.
*/
-public class KeyguardClockSwitchController extends ViewController<KeyguardClockSwitch> {
+public class KeyguardClockSwitchController extends ViewController<KeyguardClockSwitch>
+ implements Dumpable {
private static final boolean CUSTOM_CLOCKS_ENABLED = true;
private final StatusBarStateController mStatusBarStateController;
@@ -77,6 +83,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
private final LockscreenSmartspaceController mSmartspaceController;
private final Resources mResources;
private final SecureSettings mSecureSettings;
+ private final DumpManager mDumpManager;
/**
* Clock for both small and large sizes
@@ -90,7 +97,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
private int mCurrentClockSize = SMALL;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final KeyguardBypassController mBypassController;
private int mKeyguardClockTopMargin = 0;
@@ -135,12 +141,12 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
BroadcastDispatcher broadcastDispatcher,
BatteryController batteryController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- KeyguardBypassController bypassController,
LockscreenSmartspaceController smartspaceController,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
SecureSettings secureSettings,
@Main Executor uiExecutor,
- @Main Resources resources) {
+ @Main Resources resources,
+ DumpManager dumpManager) {
super(keyguardClockSwitch);
mStatusBarStateController = statusBarStateController;
mColorExtractor = colorExtractor;
@@ -150,12 +156,12 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mBroadcastDispatcher = broadcastDispatcher;
mBatteryController = batteryController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mBypassController = bypassController;
mSmartspaceController = smartspaceController;
mResources = resources;
mSecureSettings = secureSettings;
mUiExecutor = uiExecutor;
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
+ mDumpManager = dumpManager;
mKeyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(
new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() {
@Override
@@ -210,6 +216,9 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mKeyguardUpdateMonitor,
mResources);
mLargeClockViewController.init();
+
+ mDumpManager.unregisterDumpable(getClass().toString()); // unregister previous clocks
+ mDumpManager.registerDumpable(getClass().toString(), this);
}
@Override
@@ -292,8 +301,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
private void updateClockLayout() {
int largeClockTopMargin = getContext().getResources().getDimensionPixelSize(
- R.dimen.keyguard_large_clock_top_margin);
-
+ R.dimen.keyguard_large_clock_top_margin)
+ - (int) mLargeClockViewController.getBottom();
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT,
MATCH_PARENT);
lp.topMargin = largeClockTopMargin;
@@ -486,4 +495,13 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mStatusArea.setClipChildren(clip);
}
}
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("currentClockSizeLarge=" + (mCurrentClockSize == LARGE));
+ pw.println("mCanShowDoubleLineClock=" + mCanShowDoubleLineClock);
+ mClockViewController.dump(pw);
+ mLargeClockViewController.dump(pw);
+ }
}
+
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index fcabbbca6e34..3b8a29bfe8c4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -3562,8 +3562,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
pw.println(" udfpsEnrolled=" + isUdfpsEnrolled());
pw.println(" shouldListenForUdfps=" + shouldListenForFingerprint(true));
pw.println(" bouncerVisible=" + mBouncer);
- pw.println(" mStatusBarState="
- + StatusBarState.toShortString(mStatusBarState));
+ pw.println(" mStatusBarState=" + StatusBarState.toString(mStatusBarState));
}
}
if (mFaceManager != null && mFaceManager.isHardwareDetected()) {
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 6f0cd47a3f70..ffded659c2ac 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -394,7 +394,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
pw.println(" mUserUnlockedWithBiometric: " + mUserUnlockedWithBiometric);
pw.println(" mRunningFPS: " + mRunningFPS);
pw.println(" mCanDismissLockScreen: " + mCanDismissLockScreen);
- pw.println(" mStatusBarState: " + StatusBarState.toShortString(mStatusBarState));
+ pw.println(" mStatusBarState: " + StatusBarState.toString(mStatusBarState));
pw.println(" mQsExpanded: " + mQsExpanded);
pw.println(" mInterpolatedDarkAmount: " + mInterpolatedDarkAmount);
@@ -652,7 +652,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
// pre-emptively set to true to hide view
mIsBouncerShowing = true;
if (mUdfpsSupported && mShowUnlockIcon && mAuthRippleController != null) {
- mAuthRippleController.showRipple(FINGERPRINT);
+ mAuthRippleController.showUnlockRipple(FINGERPRINT);
}
updateVisibility();
if (mOnGestureDetectedRunnable != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
index 22c69373336f..011881354e35 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
@@ -369,10 +369,15 @@ class ScreenDecorHwcLayer(context: Context, displayDecorationSupport: DisplayDec
* Update the rounded corner size.
*/
fun updateRoundedCornerSize(top: Int, bottom: Int) {
+ if (roundedCornerTopSize == top && roundedCornerBottomSize == bottom) {
+ return
+ }
roundedCornerTopSize = top
roundedCornerBottomSize = bottom
updateRoundedCornerDrawableBounds()
- invalidate()
+
+ // Use requestLayout() to trigger transparent region recalculated
+ requestLayout()
}
private fun updateRoundedCornerDrawableBounds() {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 2ec9174caee6..ede2945be29a 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -1045,13 +1045,22 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
mExecutor.execute(() -> {
if (mOverlays == null) return;
if (SIZE.equals(key)) {
+ boolean hasReloadRoundedCornerRes = false;
if (newValue != null) {
try {
mRoundedCornerResDelegate.updateTuningSizeFactor(
Integer.parseInt(newValue));
+ hasReloadRoundedCornerRes = true;
} catch (Exception e) {
}
}
+
+ // When onTuningChanged() is not called through updateRoundedCornerRadii(),
+ // we need to reload rounded corner res to prevent incorrect dimen
+ if (!hasReloadRoundedCornerRes) {
+ mRoundedCornerResDelegate.reloadAll(mDisplayUniqueId);
+ }
+
updateRoundedCornerSize(
mRoundedCornerResDelegate.getTopRoundedSize(),
mRoundedCornerResDelegate.getBottomRoundedSize());
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index b811c51c952b..0cde745d2e12 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -52,7 +52,11 @@ import javax.inject.Inject
import javax.inject.Provider
/***
- * Controls the ripple effect that shows when authentication is successful.
+ * Controls two ripple effects:
+ * 1. Unlocked ripple: shows when authentication is successful
+ * 2. UDFPS dwell ripple: shows when the user has their finger down on the UDFPS area and reacts
+ * to errors and successes
+ *
* The ripple uses the accent color of the current theme.
*/
@CentralSurfacesScope
@@ -115,7 +119,7 @@ class AuthRippleController @Inject constructor(
notificationShadeWindowController.setForcePluginOpen(false, this)
}
- fun showRipple(biometricSourceType: BiometricSourceType?) {
+ fun showUnlockRipple(biometricSourceType: BiometricSourceType?) {
if (!(keyguardUpdateMonitor.isKeyguardVisible || keyguardUpdateMonitor.isDreaming) ||
keyguardUpdateMonitor.userNeedsStrongAuth()) {
return
@@ -252,11 +256,16 @@ class AuthRippleController @Inject constructor(
biometricSourceType: BiometricSourceType?,
isStrongBiometric: Boolean
) {
- showRipple(biometricSourceType)
+ if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
+ mView.fadeDwellRipple()
+ }
+ showUnlockRipple(biometricSourceType)
}
override fun onBiometricAuthFailed(biometricSourceType: BiometricSourceType?) {
- mView.retractRipple()
+ if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
+ mView.retractDwellRipple()
+ }
}
override fun onBiometricAcquired(
@@ -264,8 +273,16 @@ class AuthRippleController @Inject constructor(
acquireInfo: Int
) {
if (biometricSourceType == BiometricSourceType.FINGERPRINT &&
- acquireInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_PARTIAL) {
- mView.retractRipple()
+ BiometricFingerprintConstants.shouldTurnOffHbm(acquireInfo) &&
+ acquireInfo != BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD) {
+ // received an 'acquiredBad' message, so immediately retract
+ mView.retractDwellRipple()
+ }
+ }
+
+ override fun onKeyguardBouncerChanged(bouncerIsOrWillBeShowing: Boolean) {
+ if (bouncerIsOrWillBeShowing) {
+ mView.fadeDwellRipple()
}
}
}
@@ -294,7 +311,7 @@ class AuthRippleController @Inject constructor(
}
override fun onFingerUp() {
- mView.retractRipple()
+ mView.retractDwellRipple()
}
}
@@ -337,12 +354,12 @@ class AuthRippleController @Inject constructor(
"fingerprint" -> {
updateSensorLocation()
pw.println("fingerprint ripple sensorLocation=$fingerprintSensorLocation")
- showRipple(BiometricSourceType.FINGERPRINT)
+ showUnlockRipple(BiometricSourceType.FINGERPRINT)
}
"face" -> {
updateSensorLocation()
pw.println("face ripple sensorLocation=$faceSensorLocation")
- showRipple(BiometricSourceType.FACE)
+ showUnlockRipple(BiometricSourceType.FACE)
}
"custom" -> {
if (args.size != 3 ||
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index d67363079e17..378ae14f0327 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -35,12 +35,13 @@ import com.android.systemui.statusbar.charging.RippleShader
private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f
/**
- * Expanding ripple effect
- * - startUnlockedRipple for the transition from biometric authentication success to showing
- * launcher.
- * - startDwellRipple for the ripple expansion out when the user has their finger down on the UDFPS
- * sensor area
- * - retractRipple for the ripple animation inwards to signal a failure
+ * Handles two ripple effects: dwell ripple and unlocked ripple
+ * Dwell Ripple:
+ * - startDwellRipple: dwell ripple expands outwards around the biometric area
+ * - retractDwellRipple: retracts the dwell ripple to radius 0 to signal a failure
+ * - fadeDwellRipple: fades the dwell ripple away to alpha 0
+ * Unlocked ripple:
+ * - startUnlockedRipple: ripple expands from biometric auth location to the edges of the screen
*/
class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
private val retractInterpolator = PathInterpolator(.05f, .93f, .1f, 1f)
@@ -52,6 +53,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
private var drawRipple: Boolean = false
private var lockScreenColorVal = Color.WHITE
+ private val fadeDuration = 83L
private val retractDuration = 400L
private var alphaInDuration: Long = 0
private var unlockedRippleInProgress: Boolean = false
@@ -59,7 +61,8 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
private val dwellPaint = Paint()
private val rippleShader = RippleShader()
private val ripplePaint = Paint()
- private var retractAnimator: Animator? = null
+ private var fadeDwellAnimator: Animator? = null
+ private var retractDwellAnimator: Animator? = null
private var dwellPulseOutAnimator: Animator? = null
private var dwellRadius: Float = 0f
set(value) {
@@ -112,15 +115,15 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
}
/**
- * Animate ripple inwards back to radius 0
+ * Animate dwell ripple inwards back to radius 0
*/
- fun retractRipple() {
- if (retractAnimator?.isRunning == true) {
+ fun retractDwellRipple() {
+ if (retractDwellAnimator?.isRunning == true || fadeDwellAnimator?.isRunning == true) {
return // let the animation finish
}
if (dwellPulseOutAnimator?.isRunning == true) {
- val retractRippleAnimator = ValueAnimator.ofFloat(dwellShader.progress, 0f)
+ val retractDwellRippleAnimator = ValueAnimator.ofFloat(dwellShader.progress, 0f)
.apply {
interpolator = retractInterpolator
duration = retractDuration
@@ -145,8 +148,8 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
}
}
- retractAnimator = AnimatorSet().apply {
- playTogether(retractRippleAnimator, retractAlphaAnimator)
+ retractDwellAnimator = AnimatorSet().apply {
+ playTogether(retractDwellRippleAnimator, retractAlphaAnimator)
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationStart(animation: Animator?) {
dwellPulseOutAnimator?.cancel()
@@ -164,6 +167,42 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
}
/**
+ * Animate ripple fade to alpha=0
+ */
+ fun fadeDwellRipple() {
+ if (fadeDwellAnimator?.isRunning == true) {
+ return // let the animation finish
+ }
+
+ if (dwellPulseOutAnimator?.isRunning == true || retractDwellAnimator?.isRunning == true) {
+ fadeDwellAnimator = ValueAnimator.ofInt(Color.alpha(dwellShader.color), 0).apply {
+ interpolator = Interpolators.LINEAR
+ duration = fadeDuration
+ addUpdateListener { animator ->
+ dwellShader.color = ColorUtils.setAlphaComponent(
+ dwellShader.color,
+ animator.animatedValue as Int
+ )
+ invalidate()
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animation: Animator?) {
+ retractDwellAnimator?.cancel()
+ dwellPulseOutAnimator?.cancel()
+ drawDwell = true
+ }
+
+ override fun onAnimationEnd(animation: Animator?) {
+ drawDwell = false
+ resetDwellAlpha()
+ }
+ })
+ start()
+ }
+ }
+ }
+
+ /**
* Plays a ripple animation that grows to the dwellRadius with distortion.
*/
fun startDwellRipple(isDozing: Boolean) {
@@ -205,7 +244,8 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
)
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationStart(animation: Animator?) {
- retractAnimator?.cancel()
+ retractDwellAnimator?.cancel()
+ fadeDwellAnimator?.cancel()
visibility = VISIBLE
drawDwell = true
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index b8334a02e5f2..2a945ded08ef 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -185,7 +185,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
super.dump(fd, pw, args);
pw.println("mShowingUdfpsBouncer=" + mShowingUdfpsBouncer);
pw.println("mFaceDetectRunning=" + mFaceDetectRunning);
- pw.println("mStatusBarState=" + StatusBarState.toShortString(mStatusBarState));
+ pw.println("mStatusBarState=" + StatusBarState.toString(mStatusBarState));
pw.println("mQsExpanded=" + mQsExpanded);
pw.println("mIsBouncerVisible=" + mIsBouncerVisible);
pw.println("mInputBouncerHiddenAmount=" + mInputBouncerHiddenAmount);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
index be326da8d3bf..b325700954c2 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -77,7 +77,7 @@ class FalsingCollectorImpl implements FalsingCollector {
new StatusBarStateController.StateListener() {
@Override
public void onStateChanged(int newState) {
- logDebug("StatusBarState=" + StatusBarState.toShortString(newState));
+ logDebug("StatusBarState=" + StatusBarState.toString(newState));
mState = newState;
updateSessionActive();
}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
index b60e26628c55..6a9317f2b543 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
@@ -17,11 +17,14 @@
package com.android.systemui.clipboardoverlay;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_ENABLED;
+import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED;
+import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_UPDATED;
import android.content.ClipboardManager;
import android.content.Context;
import android.provider.DeviceConfig;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.util.DeviceConfigProxy;
@@ -38,15 +41,18 @@ public class ClipboardListener extends CoreStartable
private final DeviceConfigProxy mDeviceConfig;
private final ClipboardOverlayControllerFactory mOverlayFactory;
private final ClipboardManager mClipboardManager;
+ private final UiEventLogger mUiEventLogger;
private ClipboardOverlayController mClipboardOverlayController;
@Inject
public ClipboardListener(Context context, DeviceConfigProxy deviceConfigProxy,
- ClipboardOverlayControllerFactory overlayFactory, ClipboardManager clipboardManager) {
+ ClipboardOverlayControllerFactory overlayFactory, ClipboardManager clipboardManager,
+ UiEventLogger uiEventLogger) {
super(context);
mDeviceConfig = deviceConfigProxy;
mOverlayFactory = overlayFactory;
mClipboardManager = clipboardManager;
+ mUiEventLogger = uiEventLogger;
}
@Override
@@ -62,11 +68,15 @@ public class ClipboardListener extends CoreStartable
if (!mClipboardManager.hasPrimaryClip()) {
return;
}
+ String clipSource = mClipboardManager.getPrimaryClipSource();
if (mClipboardOverlayController == null) {
mClipboardOverlayController = mOverlayFactory.create(mContext);
+ mUiEventLogger.log(CLIPBOARD_OVERLAY_ENTERED, 0, clipSource);
+ } else {
+ mUiEventLogger.log(CLIPBOARD_OVERLAY_UPDATED, 0, clipSource);
}
mClipboardOverlayController.setClipData(
- mClipboardManager.getPrimaryClip(), mClipboardManager.getPrimaryClipSource());
+ mClipboardManager.getPrimaryClip(), clipSource);
mClipboardOverlayController.setOnSessionCompleteListener(() -> {
// Session is complete, free memory until it's needed again.
mClipboardOverlayController = null;
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index be2397d37bed..9861392ba463 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -21,6 +21,12 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
+import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ACTION_TAPPED;
+import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_EDIT_TAPPED;
+import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED;
+import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
+import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TIMED_OUT;
+
import static java.util.Objects.requireNonNull;
import android.animation.Animator;
@@ -71,6 +77,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.policy.PhoneWindow;
import com.android.systemui.R;
import com.android.systemui.screenshot.DraggableConstraintLayout;
@@ -97,6 +104,7 @@ public class ClipboardOverlayController {
private static final int SWIPE_PADDING_DP = 12; // extra padding around views to allow swipe
private final Context mContext;
+ private final UiEventLogger mUiEventLogger;
private final DisplayManager mDisplayManager;
private final DisplayMetrics mDisplayMetrics;
private final WindowManager mWindowManager;
@@ -129,11 +137,14 @@ public class ClipboardOverlayController {
private boolean mBlockAttach = false;
- public ClipboardOverlayController(Context context, TimeoutHandler timeoutHandler) {
+ public ClipboardOverlayController(
+ Context context, TimeoutHandler timeoutHandler, UiEventLogger uiEventLogger) {
mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class));
final Context displayContext = context.createDisplayContext(getDefaultDisplay());
mContext = displayContext.createWindowContext(TYPE_SCREENSHOT, null);
+ mUiEventLogger = uiEventLogger;
+
mAccessibilityManager = AccessibilityManager.getInstance(mContext);
mTextClassifier = requireNonNull(context.getSystemService(TextClassificationManager.class))
.getTextClassifier();
@@ -175,6 +186,7 @@ public class ClipboardOverlayController {
@Override
public void onSwipeDismissInitiated(Animator animator) {
+ mUiEventLogger.log(CLIPBOARD_OVERLAY_SWIPE_DISMISSED);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
@@ -222,7 +234,10 @@ public class ClipboardOverlayController {
mView.post(this::animateIn);
});
- mTimeoutHandler.setOnTimeoutRunnable(this::animateOut);
+ mTimeoutHandler.setOnTimeoutRunnable(() -> {
+ mUiEventLogger.log(CLIPBOARD_OVERLAY_TIMED_OUT);
+ animateOut();
+ });
mCloseDialogsReceiver = new BroadcastReceiver() {
@Override
@@ -306,7 +321,10 @@ public class ClipboardOverlayController {
chip.setText(action.getTitle());
chip.setContentDescription(action.getTitle());
chip.setIcon(action.getIcon(), false);
- chip.setPendingIntent(action.getActionIntent(), this::animateOut);
+ chip.setPendingIntent(action.getActionIntent(), () -> {
+ mUiEventLogger.log(CLIPBOARD_OVERLAY_ACTION_TAPPED);
+ animateOut();
+ });
chip.setAlpha(1);
return chip;
}
@@ -350,6 +368,7 @@ public class ClipboardOverlayController {
}
private void editImage(Uri uri) {
+ mUiEventLogger.log(CLIPBOARD_OVERLAY_EDIT_TAPPED);
String editorPackage = mContext.getString(R.string.config_screenshotEditor);
Intent editIntent = new Intent(Intent.ACTION_EDIT);
if (!TextUtils.isEmpty(editorPackage)) {
@@ -363,6 +382,7 @@ public class ClipboardOverlayController {
}
private void editText() {
+ mUiEventLogger.log(CLIPBOARD_OVERLAY_EDIT_TAPPED);
Intent editIntent = new Intent(mContext, EditTextActivity.class);
editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
mContext.startActivity(editIntent);
@@ -370,6 +390,7 @@ public class ClipboardOverlayController {
}
private void showNearby() {
+ mUiEventLogger.log(CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED);
mContext.startActivity(getRemoteCopyIntent());
animateOut();
}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerFactory.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerFactory.java
index e1c11c4e8b4d..275d295613f9 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerFactory.java
@@ -18,6 +18,7 @@ package com.android.systemui.clipboardoverlay;
import android.content.Context;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.screenshot.TimeoutHandler;
@@ -28,14 +29,17 @@ import javax.inject.Inject;
*/
@SysUISingleton
public class ClipboardOverlayControllerFactory {
+ private final UiEventLogger mUiEventLogger;
@Inject
- public ClipboardOverlayControllerFactory() {}
+ public ClipboardOverlayControllerFactory(UiEventLogger uiEventLogger) {
+ mUiEventLogger = uiEventLogger;
+ }
/**
* One new ClipboardOverlayController, coming right up!
*/
public ClipboardOverlayController create(Context context) {
- return new ClipboardOverlayController(context, new TimeoutHandler(context));
+ return new ClipboardOverlayController(context, new TimeoutHandler(context), mUiEventLogger);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayEvent.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayEvent.java
new file mode 100644
index 000000000000..5604a9128261
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayEvent.java
@@ -0,0 +1,50 @@
+/*
+ * 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.clipboardoverlay;
+
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+
+public enum ClipboardOverlayEvent implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "clipboard overlay entered")
+ CLIPBOARD_OVERLAY_ENTERED(949),
+ @UiEvent(doc = "clipboard overlay updated")
+ CLIPBOARD_OVERLAY_UPDATED(950),
+ @UiEvent(doc = "clipboard edit tapped")
+ CLIPBOARD_OVERLAY_EDIT_TAPPED(951),
+ @UiEvent(doc = "clipboard action tapped")
+ CLIPBOARD_OVERLAY_ACTION_TAPPED(952),
+ @UiEvent(doc = "clipboard remote copy tapped")
+ CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED(953),
+ @UiEvent(doc = "clipboard overlay timed out")
+ CLIPBOARD_OVERLAY_TIMED_OUT(954),
+ @UiEvent(doc = "clipboard overlay dismiss tapped")
+ CLIPBOARD_OVERLAY_DISMISS_TAPPED(955),
+ @UiEvent(doc = "clipboard overlay swipe dismissed")
+ CLIPBOARD_OVERLAY_SWIPE_DISMISSED(956);
+
+ private final int mId;
+
+ ClipboardOverlayEvent(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
index 1621cbc0be72..f710d0154060 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
@@ -34,7 +34,8 @@ import com.android.systemui.R;
/**
* Lightweight activity for editing text clipboard contents
*/
-public class EditTextActivity extends Activity {
+public class EditTextActivity extends Activity
+ implements ClipboardManager.OnPrimaryClipChangedListener {
private static final String TAG = "EditTextActivity";
private EditText mEditText;
@@ -71,6 +72,18 @@ public class EditTextActivity extends Activity {
}
mEditText.setText(clip.getItemAt(0).getText());
mEditText.requestFocus();
+ mClipboardManager.addPrimaryClipChangedListener(this);
+ }
+
+ @Override
+ protected void onPause() {
+ mClipboardManager.removePrimaryClipChangedListener(this);
+ super.onPause();
+ }
+
+ @Override // ClipboardManager.OnPrimaryClipChangedListener
+ public void onPrimaryClipChanged() {
+ hideImeAndFinish();
}
private void saveToClipboard() {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index f6aeb2ac4ebc..041de05aa3d4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -36,6 +36,7 @@ import android.view.IWindowManager;
import android.view.LayoutInflater;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -296,7 +297,8 @@ public class DependencyProvider {
/***/
@Provides
@SysUISingleton
- public ClipboardOverlayControllerFactory provideClipboardOverlayControllerFactory() {
- return new ClipboardOverlayControllerFactory();
+ public ClipboardOverlayControllerFactory provideClipboardOverlayControllerFactory(
+ UiEventLogger uiEventLogger) {
+ return new ClipboardOverlayControllerFactory(uiEventLogger);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 59fcf87c5029..7b65f453815c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -45,7 +45,6 @@ import com.android.systemui.lowlightclock.LowLightClockController;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationBarComponent;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
-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;
@@ -72,6 +71,7 @@ import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.policy.dagger.SmartRepliesInflationModule;
import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule;
@@ -198,25 +198,43 @@ public abstract class SystemUIModule {
static Optional<BubblesManager> provideBubblesManager(Context context,
Optional<Bubbles> bubblesOptional,
NotificationShadeWindowController notificationShadeWindowController,
- StatusBarStateController statusBarStateController, ShadeController shadeController,
+ KeyguardStateController keyguardStateController,
+ ShadeController shadeController,
ConfigurationController configurationController,
@Nullable IStatusBarService statusBarService,
INotificationManager notificationManager,
NotificationVisibilityProvider visibilityProvider,
NotificationInterruptStateProvider interruptionStateProvider,
- ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager,
- NotificationGroupManagerLegacy groupManager, NotificationEntryManager entryManager,
+ ZenModeController zenModeController,
+ NotificationLockscreenUserManager notifUserManager,
+ NotificationGroupManagerLegacy groupManager,
+ NotificationEntryManager entryManager,
CommonNotifCollection notifCollection,
- NotifPipeline notifPipeline, SysUiState sysUiState,
- NotifPipelineFlags notifPipelineFlags, DumpManager dumpManager,
+ NotifPipeline notifPipeline,
+ SysUiState sysUiState,
+ NotifPipelineFlags notifPipelineFlags,
+ DumpManager dumpManager,
@Main Executor sysuiMainExecutor) {
- return Optional.ofNullable(BubblesManager.create(context, bubblesOptional,
- notificationShadeWindowController, statusBarStateController, shadeController,
- configurationController, statusBarService, notificationManager,
+ return Optional.ofNullable(BubblesManager.create(context,
+ bubblesOptional,
+ notificationShadeWindowController,
+ keyguardStateController,
+ shadeController,
+ configurationController,
+ statusBarService,
+ notificationManager,
visibilityProvider,
- interruptionStateProvider, zenModeController, notifUserManager,
- groupManager, entryManager, notifCollection, notifPipeline, sysUiState,
- notifPipelineFlags, dumpManager, sysuiMainExecutor));
+ interruptionStateProvider,
+ zenModeController,
+ notifUserManager,
+ groupManager,
+ entryManager,
+ notifCollection,
+ notifPipeline,
+ sysUiState,
+ notifPipelineFlags,
+ dumpManager,
+ sysuiMainExecutor));
}
@BindsOptionalOf
diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
index c817f89c7a9b..4c444175eca1 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
@@ -56,17 +56,17 @@ class RoundedCornerResDelegate(
private set
init {
- reloadDrawables()
+ reloadRes()
reloadMeasures()
}
fun reloadAll(newDisplayUniqueId: String?) {
displayUniqueId = newDisplayUniqueId
- reloadDrawables()
+ reloadRes()
reloadMeasures()
}
- private fun reloadDrawables() {
+ private fun reloadRes() {
val configIdx = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId)
isMultipleRadius = getIsMultipleRadius(configIdx)
@@ -85,34 +85,6 @@ class RoundedCornerResDelegate(
arrayResId = R.array.config_roundedCornerBottomDrawableArray,
backupDrawableId = R.drawable.rounded_corner_bottom
) ?: roundedDrawable
-
- // If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the
- // (width, height) size of drawable/rounded.xml instead of rounded_corner_radius
- if (isMultipleRadius) {
- roundedSize = Size(
- roundedDrawable?.intrinsicWidth ?: 0,
- roundedDrawable?.intrinsicHeight ?: 0)
- topRoundedDrawable?.let {
- topRoundedSize = Size(it.intrinsicWidth, it.intrinsicHeight)
- }
- bottomRoundedDrawable?.let {
- bottomRoundedSize = Size(it.intrinsicWidth, it.intrinsicHeight)
- }
- } else {
- val defaultRadius = RoundedCorners.getRoundedCornerRadius(res, displayUniqueId)
- val topRadius = RoundedCorners.getRoundedCornerTopRadius(res, displayUniqueId)
- val bottomRadius = RoundedCorners.getRoundedCornerBottomRadius(res, displayUniqueId)
- roundedSize = Size(defaultRadius, defaultRadius)
- topRoundedSize = Size(topRadius, topRadius)
- bottomRoundedSize = Size(bottomRadius, bottomRadius)
- }
-
- if (topRoundedSize.width == 0) {
- topRoundedSize = roundedSize
- }
- if (bottomRoundedSize.width == 0) {
- bottomRoundedSize = roundedSize
- }
}
private fun reloadMeasures(roundedSizeFactor: Int? = null) {
@@ -137,17 +109,18 @@ class RoundedCornerResDelegate(
bottomRoundedSize = Size(bottomRadius, bottomRadius)
}
- roundedSizeFactor ?.let {
- val length: Int = (it * density).toInt()
- roundedSize = Size(length, length)
- }
-
if (topRoundedSize.width == 0) {
topRoundedSize = roundedSize
}
if (bottomRoundedSize.width == 0) {
bottomRoundedSize = roundedSize
}
+
+ if (roundedSizeFactor != null && roundedSizeFactor > 0) {
+ val length: Int = (roundedSizeFactor * density).toInt()
+ topRoundedSize = Size(length, length)
+ bottomRoundedSize = Size(length, length)
+ }
}
fun updateTuningSizeFactor(factor: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java
index aaa34ed32c7e..6589f26dbde2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java
@@ -21,6 +21,7 @@ import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
import com.android.systemui.statusbar.policy.CallbackController;
@@ -30,6 +31,7 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -78,10 +80,16 @@ public class DreamOverlayNotificationCountProvider
@Inject
public DreamOverlayNotificationCountProvider(
- NotificationListener notificationListener) {
+ NotificationListener notificationListener,
+ @Background Executor bgExecutor) {
notificationListener.addNotificationHandler(mNotificationHandler);
- Arrays.stream(notificationListener.getActiveNotifications())
- .forEach(sbn -> mNotificationKeys.add(sbn.getKey()));
+
+ bgExecutor.execute(() -> {
+ Arrays.stream(notificationListener.getActiveNotifications())
+ .forEach(sbn -> mNotificationKeys.add(sbn.getKey()));
+ reportNotificationCountChanged();
+ }
+ );
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 88555edd1e8b..b96eee717260 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -102,7 +102,7 @@ public class KeyguardService extends Service {
"persist.wm.enable_remote_keyguard_animation";
private static final int sEnableRemoteKeyguardAnimation =
- SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 1);
+ SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 2);
/**
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0486fee4239d..890ddf0d6cac 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -47,6 +47,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
+import android.graphics.Matrix;
import android.hardware.biometrics.BiometricSourceType;
import android.media.AudioAttributes;
import android.media.AudioManager;
@@ -236,6 +237,14 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
*/
private static final int KEYGUARD_DONE_DRAWING_TIMEOUT_MS = 2000;
+ private static final int UNOCCLUDE_ANIMATION_DURATION = 250;
+
+ /**
+ * How far down to animate the unoccluding activity, in terms of percent of the activity's
+ * height.
+ */
+ private static final float UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT = 0.1f;
+
/**
* Boolean option for doKeyguardLocked/doKeyguardTimeout which, when set to true, forces the
* keyguard to show even if it is disabled for the current user.
@@ -883,53 +892,91 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
}
};
+ private IRemoteAnimationRunner mOccludeAnimationRunner =
+ new ActivityLaunchRemoteAnimationRunner(mOccludeAnimationController);
+
/**
- * Animation controller for activities that unocclude the keyguard. This will play the launch
- * animation in reverse.
+ * Animation controller for activities that unocclude the keyguard. This does not use the
+ * ActivityLaunchAnimator since we're just translating down, rather than emerging from a view
+ * or the power button.
*/
- private final ActivityLaunchAnimator.Controller mUnoccludeAnimationController =
- new ActivityLaunchAnimator.Controller() {
- @Override
- public void onLaunchAnimationEnd(boolean isExpandingFullyAbove) {
- setOccluded(false /* isOccluded */, false /* animate */);
- }
+ private final IRemoteAnimationRunner mUnoccludeAnimationRunner =
+ new IRemoteAnimationRunner.Stub() {
- @Override
- public void onLaunchAnimationCancelled() {
- setOccluded(false /* isOccluded */, false /* animate */);
- }
+ @Nullable private ValueAnimator mUnoccludeAnimator;
+ private final Matrix mUnoccludeMatrix = new Matrix();
- @NonNull
@Override
- public ViewGroup getLaunchContainer() {
- return ((ViewGroup) mKeyguardViewControllerLazy.get()
- .getViewRootImpl().getView());
+ public void onAnimationCancelled() {
+ if (mUnoccludeAnimator != null) {
+ mUnoccludeAnimator.cancel();
+ }
}
@Override
- public void setLaunchContainer(@NonNull ViewGroup launchContainer) {
- // No-op, launch container is always the shade.
- Log.wtf(TAG, "Someone tried to change the launch container for the "
- + "ActivityLaunchAnimator, which should never happen.");
- }
+ public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers,
+ RemoteAnimationTarget[] nonApps,
+ IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
+ final RemoteAnimationTarget primary = apps[0];
- @NonNull
- @Override
- public LaunchAnimator.State createAnimatorState() {
- final int width = getLaunchContainer().getWidth();
- final int height = getLaunchContainer().getHeight();
+ if (primary == null) {
+ finishedCallback.onAnimationFinished();
+ return;
+ }
- // TODO(b/207399883): Unocclude animation. This currently ends instantly.
- return new LaunchAnimator.State(
- 0, height, 0, width, mWindowCornerRadius, mWindowCornerRadius);
+ final SyncRtSurfaceTransactionApplier applier =
+ new SyncRtSurfaceTransactionApplier(
+ mKeyguardViewControllerLazy.get().getViewRootImpl().getView());
+
+
+ mContext.getMainExecutor().execute(() -> {
+ if (mUnoccludeAnimator != null) {
+ mUnoccludeAnimator.cancel();
+ }
+
+ mUnoccludeAnimator = ValueAnimator.ofFloat(1f, 0f);
+ mUnoccludeAnimator.setDuration(UNOCCLUDE_ANIMATION_DURATION);
+ mUnoccludeAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE);
+ mUnoccludeAnimator.addUpdateListener(
+ animation -> {
+ final float animatedValue =
+ (float) animation.getAnimatedValue();
+
+ final float surfaceHeight = primary.screenSpaceBounds.height();
+
+ mUnoccludeMatrix.setTranslate(
+ 0f,
+ (1f - animatedValue)
+ * surfaceHeight
+ * UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT);
+
+ SyncRtSurfaceTransactionApplier.SurfaceParams params =
+ new SyncRtSurfaceTransactionApplier.SurfaceParams
+ .Builder(primary.leash)
+ .withMatrix(mUnoccludeMatrix)
+ .withCornerRadius(mWindowCornerRadius)
+ .withAlpha(animatedValue)
+ .build();
+ applier.scheduleApply(params);
+ });
+ mUnoccludeAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ try {
+ finishedCallback.onAnimationFinished();
+ mUnoccludeAnimator = null;
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ mUnoccludeAnimator.start();
+ });
}
};
- private IRemoteAnimationRunner mOccludeAnimationRunner =
- new ActivityLaunchRemoteAnimationRunner(mOccludeAnimationController);
- private IRemoteAnimationRunner mUnoccludeAnimationRunner =
- new ActivityLaunchRemoteAnimationRunner(mUnoccludeAnimationController);
-
private DeviceConfigProxy mDeviceConfig;
private DozeParameters mDozeParameters;
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 20029fec4dd1..d4e2214f8b38 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -12,6 +12,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.annotation.VisibleForTesting
+import com.android.internal.logging.InstanceId
import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.classifier.FalsingCollector
@@ -59,7 +60,7 @@ class MediaCarouselController @Inject constructor(
falsingCollector: FalsingCollector,
falsingManager: FalsingManager,
dumpManager: DumpManager,
- private val mediaFlags: MediaFlags
+ private val logger: MediaUiEventLogger
) : Dumpable {
/**
* The current width of the carousel
@@ -119,7 +120,9 @@ class MediaCarouselController @Inject constructor(
private val mediaCarousel: MediaScrollView
val mediaCarouselScrollHandler: MediaCarouselScrollHandler
val mediaFrame: ViewGroup
- private lateinit var settingsButton: View
+ @VisibleForTesting
+ lateinit var settingsButton: View
+ private set
private val mediaContent: ViewGroup
private val pageIndicator: PageIndicator
private val visualStabilityCallback: OnReorderingAllowedListener
@@ -183,7 +186,8 @@ class MediaCarouselController @Inject constructor(
pageIndicator = mediaFrame.requireViewById(R.id.media_page_indicator)
mediaCarouselScrollHandler = MediaCarouselScrollHandler(mediaCarousel, pageIndicator,
executor, this::onSwipeToDismiss, this::updatePageIndicatorLocation,
- this::closeGuts, falsingCollector, falsingManager, this::logSmartspaceImpression)
+ this::closeGuts, falsingCollector, falsingManager, this::logSmartspaceImpression,
+ logger)
isRtl = context.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
inflateSettingsButton()
mediaContent = mediaCarousel.requireViewById(R.id.media_carousel)
@@ -220,7 +224,7 @@ class MediaCarouselController @Inject constructor(
MediaPlayerData.getMediaPlayer(key)?.let {
/* ktlint-disable max-line-length */
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
- it.mInstanceId,
+ it.mSmartspaceId,
it.mUid,
/* isRecommendationCard */ false,
intArrayOf(
@@ -239,12 +243,12 @@ class MediaCarouselController @Inject constructor(
// resume card is ranked first
MediaPlayerData.players().forEachIndexed { index, it ->
if (it.recommendationViewHolder == null) {
- it.mInstanceId = SmallHash.hash(it.mUid +
+ it.mSmartspaceId = SmallHash.hash(it.mUid +
systemClock.currentTimeMillis().toInt())
it.mIsImpressed = false
/* ktlint-disable max-line-length */
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
- it.mInstanceId,
+ it.mSmartspaceId,
it.mUid,
/* isRecommendationCard */ false,
intArrayOf(
@@ -291,12 +295,12 @@ class MediaCarouselController @Inject constructor(
// recommendation card is valid and ranked first
MediaPlayerData.players().forEachIndexed { index, it ->
if (it.recommendationViewHolder == null) {
- it.mInstanceId = SmallHash.hash(it.mUid +
+ it.mSmartspaceId = SmallHash.hash(it.mUid +
systemClock.currentTimeMillis().toInt())
it.mIsImpressed = false
/* ktlint-disable max-line-length */
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
- it.mInstanceId,
+ it.mSmartspaceId,
it.mUid,
/* isRecommendationCard */ false,
intArrayOf(
@@ -312,7 +316,7 @@ class MediaCarouselController @Inject constructor(
MediaPlayerData.getMediaPlayer(key)?.let {
/* ktlint-disable max-line-length */
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
- it.mInstanceId,
+ it.mSmartspaceId,
it.mUid,
/* isRecommendationCard */ true,
intArrayOf(
@@ -369,6 +373,7 @@ class MediaCarouselController @Inject constructor(
mediaFrame.addView(settingsButton)
mediaCarouselScrollHandler.onSettingsButtonUpdated(settings)
settingsButton.setOnClickListener {
+ logger.logCarouselSettings()
activityStarter.startActivity(settingsIntent, true /* dismissShade */)
}
}
@@ -752,7 +757,7 @@ class MediaCarouselController @Inject constructor(
return
}
logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN
- mediaControlPanel.mInstanceId,
+ mediaControlPanel.mSmartspaceId,
mediaControlPanel.mUid,
isRecommendationCard,
intArrayOf(mediaControlPanel.surfaceForSmartspaceLogging))
@@ -836,7 +841,7 @@ class MediaCarouselController @Inject constructor(
index, it ->
if (it.mIsImpressed) {
logSmartspaceCardReported(SMARTSPACE_CARD_DISMISS_EVENT,
- it.mInstanceId,
+ it.mSmartspaceId,
it.mUid,
it.recommendationViewHolder != null,
intArrayOf(it.surfaceForSmartspaceLogging),
@@ -846,6 +851,7 @@ class MediaCarouselController @Inject constructor(
it.mIsImpressed = false
}
}
+ logger.logSwipeDismiss()
mediaManager.onSwipeToDismiss()
}
@@ -881,7 +887,9 @@ internal object MediaPlayerData {
clickIntent = null,
device = null,
active = true,
- resumeAction = null)
+ resumeAction = null,
+ instanceId = InstanceId.fakeInstanceId(-1),
+ appUid = -1)
// Whether should prioritize Smartspace card.
internal var shouldPrioritizeSs: Boolean = false
private set
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
index 5dc4bcfa92ff..ef49fd35d703 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
@@ -57,12 +57,13 @@ class MediaCarouselScrollHandler(
private val scrollView: MediaScrollView,
private val pageIndicator: PageIndicator,
private val mainExecutor: DelayableExecutor,
- private val dismissCallback: () -> Unit,
+ val dismissCallback: () -> Unit,
private var translationChangedListener: () -> Unit,
private val closeGuts: (immediate: Boolean) -> Unit,
private val falsingCollector: FalsingCollector,
private val falsingManager: FalsingManager,
- private val logSmartspaceImpression: (Boolean) -> Unit
+ private val logSmartspaceImpression: (Boolean) -> Unit,
+ private val logger: MediaUiEventLogger
) {
/**
* Is the view in RTL
@@ -476,6 +477,7 @@ class MediaCarouselScrollHandler(
visibleMediaIndex = newIndex
if (oldIndex != visibleMediaIndex && visibleToUser) {
logSmartspaceImpression(qsExpanded)
+ logger.logMediaCarouselPage(newIndex)
}
closeGuts(false)
updatePlayerVisibilities()
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index b815f0c447d0..7ac70bd78953 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -53,6 +53,7 @@ import androidx.annotation.UiThread;
import androidx.constraintlayout.widget.ConstraintSet;
import com.android.internal.jank.InteractionJankMonitor;
+import com.android.internal.logging.InstanceId;
import com.android.settingslib.widget.AdaptiveIcon;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -131,8 +132,6 @@ public class MediaControlPanel {
private MediaController mController;
private Lazy<MediaDataManager> mMediaDataManagerLazy;
private int mBackgroundColor;
- // Instance id for logging purpose.
- protected int mInstanceId = -1;
// Uid for the media app.
protected int mUid = Process.INVALID_UID;
private int mSmartspaceMediaItemsCount;
@@ -140,9 +139,13 @@ public class MediaControlPanel {
private final MediaOutputDialogFactory mMediaOutputDialogFactory;
private final FalsingManager mFalsingManager;
- // Used for swipe-to-dismiss logging.
+ // Used for logging.
protected boolean mIsImpressed = false;
private SystemClock mSystemClock;
+ private MediaUiEventLogger mLogger;
+ private InstanceId mInstanceId;
+ protected int mSmartspaceId = -1;
+ private String mPackageName;
/**
* Initialize a new control panel
@@ -157,7 +160,7 @@ public class MediaControlPanel {
Lazy<MediaDataManager> lazyMediaDataManager,
MediaOutputDialogFactory mediaOutputDialogFactory,
MediaCarouselController mediaCarouselController,
- FalsingManager falsingManager, SystemClock systemClock) {
+ FalsingManager falsingManager, SystemClock systemClock, MediaUiEventLogger logger) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
mActivityStarter = activityStarter;
@@ -169,8 +172,12 @@ public class MediaControlPanel {
mMediaCarouselController = mediaCarouselController;
mFalsingManager = falsingManager;
mSystemClock = systemClock;
+ mLogger = logger;
- mSeekBarViewModel.setLogSmartspaceClick(() -> {
+ mSeekBarViewModel.setLogSeek(() -> {
+ if (mPackageName != null && mInstanceId != null) {
+ mLogger.logSeek(mUid, mPackageName, mInstanceId);
+ }
logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
/* isRecommendationCard */ false);
return Unit.INSTANCE;
@@ -261,6 +268,7 @@ public class MediaControlPanel {
});
vh.getSettings().setOnClickListener(v -> {
if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ mLogger.logLongPressSettings(mUid, mPackageName, mInstanceId);
mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
}
});
@@ -301,16 +309,13 @@ public class MediaControlPanel {
}
mKey = key;
MediaSession.Token token = data.getToken();
- PackageManager packageManager = mContext.getPackageManager();
- try {
- mUid = packageManager.getApplicationInfo(data.getPackageName(), 0 /* flags */).uid;
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "Unable to look up package name", e);
- }
+ mPackageName = data.getPackageName();
+ mUid = data.getAppUid();
// Only assigns instance id if it's unassigned.
- if (mInstanceId == -1) {
- mInstanceId = SmallHash.hash(mUid + (int) mSystemClock.currentTimeMillis());
+ if (mSmartspaceId == -1) {
+ mSmartspaceId = SmallHash.hash(mUid + (int) mSystemClock.currentTimeMillis());
}
+ mInstanceId = data.getInstanceId();
mBackgroundColor = data.getBackgroundColor();
if (mToken == null || !mToken.equals(token)) {
@@ -401,6 +406,7 @@ public class MediaControlPanel {
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return;
}
+ mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId);
if (device.getIntent() != null) {
if (device.getIntent().isActivity()) {
mActivityStarter.startActivity(
@@ -413,7 +419,7 @@ public class MediaControlPanel {
}
}
} else {
- mMediaOutputDialogFactory.create(data.getPackageName(), true,
+ mMediaOutputDialogFactory.create(mPackageName, true,
mMediaViewHolder.getSeamlessButton());
}
});
@@ -437,6 +443,7 @@ public class MediaControlPanel {
logSmartspaceCardReported(SMARTSPACE_CARD_DISMISS_EVENT,
/* isRecommendationCard */ false);
+ mLogger.logLongPressDismiss(mUid, mPackageName, mInstanceId);
if (mKey != null) {
closeGuts();
@@ -675,6 +682,7 @@ public class MediaControlPanel {
button.setEnabled(true);
button.setOnClickListener(v -> {
if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ mLogger.logTapAction(button.getId(), mUid, mPackageName, mInstanceId);
logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
/* isRecommendationCard */ false);
action.run();
@@ -794,7 +802,7 @@ public class MediaControlPanel {
return;
}
- mInstanceId = SmallHash.hash(data.getTargetId());
+ mSmartspaceId = SmallHash.hash(data.getTargetId());
mBackgroundColor = data.getBackgroundColor();
TransitionLayout recommendationCard = mRecommendationViewHolder.getRecommendations();
recommendationCard.setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor));
@@ -976,6 +984,7 @@ public class MediaControlPanel {
mRecommendationViewHolder.marquee(true, mMediaViewController.GUTS_ANIMATION_DURATION);
}
mMediaViewController.openGuts();
+ mLogger.logLongPressOpen(mUid, mPackageName, mInstanceId);
}
/**
@@ -1138,7 +1147,7 @@ public class MediaControlPanel {
private void logSmartspaceCardReported(int eventId, boolean isRecommendationCard,
int interactedSubcardRank, int interactedSubcardCardinality) {
mMediaCarouselController.logSmartspaceCardReported(eventId,
- mInstanceId,
+ mSmartspaceId,
mUid,
isRecommendationCard,
new int[]{getSurfaceForSmartspaceLogging()},
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index 47a0991d3d1e..a4d2f7bc96c4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -20,6 +20,7 @@ import android.app.PendingIntent
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.media.session.MediaSession
+import com.android.internal.logging.InstanceId
import com.android.systemui.R
/** State of a media view. */
@@ -115,7 +116,17 @@ data class MediaData(
/**
* Timestamp when this player was last active.
*/
- var lastActive: Long = 0L
+ var lastActive: Long = 0L,
+
+ /**
+ * Instance ID for logging purposes
+ */
+ val instanceId: InstanceId,
+
+ /**
+ * The UID of the app, used for logging
+ */
+ val appUid: Int
) {
companion object {
/** Media is playing on the local device */
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 029ea9ad99f0..08c3395b4528 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -27,6 +27,7 @@ import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.ImageDecoder
import android.graphics.drawable.Icon
@@ -37,6 +38,7 @@ import android.media.session.MediaSession
import android.media.session.PlaybackState
import android.net.Uri
import android.os.Parcelable
+import android.os.Process
import android.os.UserHandle
import android.provider.Settings
import android.service.notification.StatusBarNotification
@@ -44,6 +46,7 @@ import android.text.TextUtils
import android.util.Log
import androidx.media.utils.MediaConstants
import com.android.internal.annotations.VisibleForTesting
+import com.android.internal.logging.InstanceId
import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -94,7 +97,9 @@ private val LOADING = MediaData(
clickIntent = null,
device = null,
active = true,
- resumeAction = null)
+ resumeAction = null,
+ instanceId = InstanceId.fakeInstanceId(-1),
+ appUid = Process.INVALID_UID)
@VisibleForTesting
internal val EMPTY_SMARTSPACE_MEDIA_DATA = SmartspaceMediaData("INVALID", false, false,
@@ -138,7 +143,8 @@ class MediaDataManager(
private val useQsMediaPlayer: Boolean,
private val systemClock: SystemClock,
private val tunerService: TunerService,
- private val mediaFlags: MediaFlags
+ private val mediaFlags: MediaFlags,
+ private val logger: MediaUiEventLogger
) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener {
companion object {
@@ -202,12 +208,13 @@ class MediaDataManager(
smartspaceMediaDataProvider: SmartspaceMediaDataProvider,
clock: SystemClock,
tunerService: TunerService,
- mediaFlags: MediaFlags
+ mediaFlags: MediaFlags,
+ logger: MediaUiEventLogger
) : this(context, backgroundExecutor, foregroundExecutor, mediaControllerFactory,
broadcastDispatcher, dumpManager, mediaTimeoutListener, mediaResumeListener,
mediaSessionBasedFilter, mediaDeviceManager, mediaDataCombineLatest, mediaDataFilter,
activityStarter, smartspaceMediaDataProvider, Utils.useMediaResumption(context),
- Utils.useQsMediaPlayer(context), clock, tunerService, mediaFlags)
+ Utils.useQsMediaPlayer(context), clock, tunerService, mediaFlags, logger)
private val appChangeReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
@@ -298,17 +305,24 @@ class MediaDataManager(
fun onNotificationAdded(key: String, sbn: StatusBarNotification) {
if (useQsMediaPlayer && isMediaNotification(sbn)) {
+ var logEvent = false
Assert.isMainThread()
val oldKey = findExistingEntry(key, sbn.packageName)
if (oldKey == null) {
- val temp = LOADING.copy(packageName = sbn.packageName)
+ val instanceId = logger.getNewInstanceId()
+ val temp = LOADING.copy(
+ packageName = sbn.packageName,
+ instanceId = instanceId
+ )
mediaEntries.put(key, temp)
+ logEvent = true
} else if (oldKey != key) {
- // Move to new key
+ // Resume -> active conversion; move to new key
val oldData = mediaEntries.remove(oldKey)!!
+ logEvent = true
mediaEntries.put(key, oldData)
}
- loadMediaData(key, sbn, oldKey)
+ loadMediaData(key, sbn, oldKey, logEvent)
} else {
onNotificationRemoved(key)
}
@@ -340,9 +354,23 @@ class MediaDataManager(
) {
// Resume controls don't have a notification key, so store by package name instead
if (!mediaEntries.containsKey(packageName)) {
- val resumeData = LOADING.copy(packageName = packageName, resumeAction = action,
- hasCheckedForResume = true)
+ val instanceId = logger.getNewInstanceId()
+ val appUid = try {
+ context.packageManager.getApplicationInfo(packageName, 0)?.uid!!
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Could not get app UID for $packageName", e)
+ Process.INVALID_UID
+ }
+
+ val resumeData = LOADING.copy(
+ packageName = packageName,
+ resumeAction = action,
+ hasCheckedForResume = true,
+ instanceId = instanceId,
+ appUid = appUid
+ )
mediaEntries.put(packageName, resumeData)
+ logger.logResumeMediaAdded(appUid, packageName, instanceId)
}
backgroundExecutor.execute {
loadMediaDataInBgForResumption(userId, desc, action, token, appName, appIntent,
@@ -368,10 +396,11 @@ class MediaDataManager(
private fun loadMediaData(
key: String,
sbn: StatusBarNotification,
- oldKey: String?
+ oldKey: String?,
+ logEvent: Boolean = false
) {
backgroundExecutor.execute {
- loadMediaDataInBg(key, sbn, oldKey)
+ loadMediaDataInBg(key, sbn, oldKey, logEvent)
}
}
@@ -449,6 +478,10 @@ class MediaDataManager(
*/
internal fun setTimedOut(key: String, timedOut: Boolean, forceUpdate: Boolean = false) {
mediaEntries[key]?.let {
+ if (timedOut && !forceUpdate) {
+ // Only log this event when media expires on its own
+ logger.logMediaTimeout(it.appUid, it.packageName, it.instanceId)
+ }
if (it.active == !timedOut && !forceUpdate) {
if (it.resumption) {
if (DEBUG) Log.d(TAG, "timing out resume player $key")
@@ -463,7 +496,9 @@ class MediaDataManager(
}
private fun removeEntry(key: String) {
- mediaEntries.remove(key)
+ mediaEntries.remove(key)?.let {
+ logger.logMediaRemoved(it.appUid, it.packageName, it.instanceId)
+ }
notifyMediaDataRemoved(key)
}
@@ -537,6 +572,10 @@ class MediaDataManager(
null
}
+ val currentEntry = mediaEntries.get(packageName)
+ val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
+ val appUid = currentEntry?.appUid ?: Process.INVALID_UID
+
val mediaAction = getResumeMediaAction(resumeAction)
val lastActive = systemClock.elapsedRealtime()
foregroundExecutor.execute {
@@ -545,14 +584,16 @@ class MediaDataManager(
MediaButton(playOrPause = mediaAction), packageName, token, appIntent,
device = null, active = false,
resumeAction = resumeAction, resumption = true, notificationKey = packageName,
- hasCheckedForResume = true, lastActive = lastActive))
+ hasCheckedForResume = true, lastActive = lastActive, instanceId = instanceId,
+ appUid = appUid))
}
}
private fun loadMediaDataInBg(
key: String,
sbn: StatusBarNotification,
- oldKey: String?
+ oldKey: String?,
+ logEvent: Boolean = false
) {
val token = sbn.notification.extras.getParcelable(Notification.EXTRA_MEDIA_SESSION)
as MediaSession.Token?
@@ -636,6 +677,22 @@ class MediaDataManager(
MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL) MediaData.PLAYBACK_LOCAL
else MediaData.PLAYBACK_CAST_LOCAL
val isPlaying = mediaController.playbackState?.let { isPlayingState(it.state) } ?: null
+
+ val currentEntry = mediaEntries.get(key)
+ val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
+ val appUid = try {
+ context.packageManager.getApplicationInfo(sbn.packageName, 0)?.uid!!
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Could not get app UID for ${sbn.packageName}", e)
+ Process.INVALID_UID
+ }
+
+ if (logEvent) {
+ logger.logActiveMediaAdded(appUid, sbn.packageName, instanceId, playbackLocation)
+ } else if (playbackLocation != currentEntry?.playbackLocation) {
+ logger.logPlaybackLocationChange(appUid, sbn.packageName, instanceId, playbackLocation)
+ }
+
val lastActive = systemClock.elapsedRealtime()
foregroundExecutor.execute {
val resumeAction: Runnable? = mediaEntries[key]?.resumeAction
@@ -647,7 +704,7 @@ class MediaDataManager(
active, resumeAction = resumeAction, playbackLocation = playbackLocation,
notificationKey = key, hasCheckedForResume = hasCheckedForResume,
isPlaying = isPlaying, isClearable = sbn.isClearable(),
- lastActive = lastActive))
+ lastActive = lastActive, instanceId = instanceId, appUid = appUid))
}
}
@@ -989,10 +1046,12 @@ class MediaDataManager(
notifyMediaDataRemoved(key)
notifyMediaDataLoaded(pkg, pkg, updated)
}
+ logger.logActiveConvertedToResume(updated.appUid, pkg, updated.instanceId)
return
}
if (removed != null) {
notifyMediaDataRemoved(key)
+ logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
}
}
@@ -1009,6 +1068,7 @@ class MediaDataManager(
filtered.forEach {
mediaEntries.remove(it.key)
notifyMediaDataRemoved(it.key)
+ logger.logMediaRemoved(it.value.appUid, it.value.packageName, it.value.instanceId)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt b/packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt
new file mode 100644
index 000000000000..862b2797b77c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2022 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.media
+
+import com.android.internal.logging.InstanceId
+import com.android.internal.logging.InstanceIdSequence
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import java.lang.IllegalArgumentException
+import javax.inject.Inject
+
+private const val INSTANCE_ID_MAX = 1 shl 20
+
+/**
+ * A helper class to log events related to the media controls
+ */
+@SysUISingleton
+class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger) {
+
+ private val instanceIdSequence = InstanceIdSequence(INSTANCE_ID_MAX)
+
+ /**
+ * Get a new instance ID for a new media control
+ */
+ fun getNewInstanceId(): InstanceId {
+ return instanceIdSequence.newInstanceId()
+ }
+
+ fun logActiveMediaAdded(
+ uid: Int,
+ packageName: String,
+ instanceId: InstanceId,
+ playbackLocation: Int
+ ) {
+ val event = when (playbackLocation) {
+ MediaData.PLAYBACK_LOCAL -> MediaUiEvent.LOCAL_MEDIA_ADDED
+ MediaData.PLAYBACK_CAST_LOCAL -> MediaUiEvent.CAST_MEDIA_ADDED
+ MediaData.PLAYBACK_CAST_REMOTE -> MediaUiEvent.REMOTE_MEDIA_ADDED
+ else -> throw IllegalArgumentException("Unknown playback location")
+ }
+ logger.logWithInstanceId(event, uid, packageName, instanceId)
+ }
+
+ fun logPlaybackLocationChange(
+ uid: Int,
+ packageName: String,
+ instanceId: InstanceId,
+ playbackLocation: Int
+ ) {
+ val event = when (playbackLocation) {
+ MediaData.PLAYBACK_LOCAL -> MediaUiEvent.TRANSFER_TO_LOCAL
+ MediaData.PLAYBACK_CAST_LOCAL -> MediaUiEvent.TRANSFER_TO_CAST
+ MediaData.PLAYBACK_CAST_REMOTE -> MediaUiEvent.TRANSFER_TO_REMOTE
+ else -> throw IllegalArgumentException("Unknown playback location")
+ }
+ logger.logWithInstanceId(event, uid, packageName, instanceId)
+ }
+
+ fun logResumeMediaAdded(uid: Int, packageName: String, instanceId: InstanceId) {
+ logger.logWithInstanceId(MediaUiEvent.RESUME_MEDIA_ADDED, uid, packageName, instanceId)
+ }
+
+ fun logActiveConvertedToResume(uid: Int, packageName: String, instanceId: InstanceId) {
+ logger.logWithInstanceId(MediaUiEvent.ACTIVE_TO_RESUME, uid, packageName, instanceId)
+ }
+
+ fun logMediaTimeout(uid: Int, packageName: String, instanceId: InstanceId) {
+ logger.logWithInstanceId(MediaUiEvent.MEDIA_TIMEOUT, uid, packageName, instanceId)
+ }
+
+ fun logMediaRemoved(uid: Int, packageName: String, instanceId: InstanceId) {
+ logger.logWithInstanceId(MediaUiEvent.MEDIA_REMOVED, uid, packageName, instanceId)
+ }
+
+ fun logMediaCarouselPage(position: Int) {
+ // Since this operation is on the carousel, we don't include package information
+ logger.logWithPosition(MediaUiEvent.CAROUSEL_PAGE, 0, null, position)
+ }
+
+ fun logSwipeDismiss() {
+ // Since this operation is on the carousel, we don't include package information
+ logger.log(MediaUiEvent.DISMISS_SWIPE)
+ }
+
+ fun logLongPressOpen(uid: Int, packageName: String, instanceId: InstanceId) {
+ logger.logWithInstanceId(MediaUiEvent.OPEN_LONG_PRESS, uid, packageName, instanceId)
+ }
+
+ fun logLongPressDismiss(uid: Int, packageName: String, instanceId: InstanceId) {
+ logger.logWithInstanceId(MediaUiEvent.DISMISS_LONG_PRESS, uid, packageName, instanceId)
+ }
+
+ fun logLongPressSettings(uid: Int, packageName: String, instanceId: InstanceId) {
+ logger.logWithInstanceId(MediaUiEvent.OPEN_SETTINGS_LONG_PRESS, uid, packageName,
+ instanceId)
+ }
+
+ fun logCarouselSettings() {
+ // Since this operation is on the carousel, we don't include package information
+ logger.log(MediaUiEvent.OPEN_SETTINGS_CAROUSEL)
+ }
+
+ fun logTapAction(buttonId: Int, uid: Int, packageName: String, instanceId: InstanceId) {
+ val event = when (buttonId) {
+ R.id.actionPlayPause -> MediaUiEvent.TAP_ACTION_PLAY_PAUSE
+ R.id.actionPrev -> MediaUiEvent.TAP_ACTION_PREV
+ R.id.actionNext -> MediaUiEvent.TAP_ACTION_NEXT
+ else -> MediaUiEvent.TAP_ACTION_OTHER
+ }
+
+ logger.logWithInstanceId(event, uid, packageName, instanceId)
+ }
+
+ fun logSeek(uid: Int, packageName: String, instanceId: InstanceId) {
+ logger.logWithInstanceId(MediaUiEvent.ACTION_SEEK, uid, packageName, instanceId)
+ }
+
+ fun logOpenOutputSwitcher(uid: Int, packageName: String, instanceId: InstanceId) {
+ logger.logWithInstanceId(MediaUiEvent.OPEN_OUTPUT_SWITCHER, uid, packageName, instanceId)
+ }
+}
+
+enum class MediaUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "A new media control was added for media playing locally on the device")
+ LOCAL_MEDIA_ADDED(1029),
+
+ @UiEvent(doc = "A new media control was added for media cast from the device")
+ CAST_MEDIA_ADDED(1030),
+
+ @UiEvent(doc = "A new media control was added for media playing remotely")
+ REMOTE_MEDIA_ADDED(1031),
+
+ @UiEvent(doc = "The media for an existing control was transferred to local playback")
+ TRANSFER_TO_LOCAL(1032),
+
+ @UiEvent(doc = "The media for an existing control was transferred to a cast device")
+ TRANSFER_TO_CAST(1033),
+
+ @UiEvent(doc = "The media for an existing control was transferred to a remote device")
+ TRANSFER_TO_REMOTE(1034),
+
+ @UiEvent(doc = "A new resumable media control was added")
+ RESUME_MEDIA_ADDED(1013),
+
+ @UiEvent(doc = "An existing active media control was converted into resumable media")
+ ACTIVE_TO_RESUME(1014),
+
+ @UiEvent(doc = "Media timed out")
+ MEDIA_TIMEOUT(1015),
+
+ @UiEvent(doc = "A media control was removed from the carousel")
+ MEDIA_REMOVED(1016),
+
+ @UiEvent(doc = "User swiped to another control within the media carousel")
+ CAROUSEL_PAGE(1017),
+
+ @UiEvent(doc = "The user swiped away the media carousel")
+ DISMISS_SWIPE(1018),
+
+ @UiEvent(doc = "The user opened the long press menu")
+ OPEN_LONG_PRESS(1019),
+
+ @UiEvent(doc = "The user dismissed via long press menu")
+ DISMISS_LONG_PRESS(1020),
+
+ @UiEvent(doc = "The user opened settings from long press menu")
+ OPEN_SETTINGS_LONG_PRESS(1021),
+
+ @UiEvent(doc = "The user opened settings from the carousel")
+ OPEN_SETTINGS_CAROUSEL(1022),
+
+ @UiEvent(doc = "The play/pause button was tapped")
+ TAP_ACTION_PLAY_PAUSE(1023),
+
+ @UiEvent(doc = "The previous button was tapped")
+ TAP_ACTION_PREV(1024),
+
+ @UiEvent(doc = "The next button was tapped")
+ TAP_ACTION_NEXT(1025),
+
+ @UiEvent(doc = "A custom or generic action button was tapped")
+ TAP_ACTION_OTHER(1026),
+
+ @UiEvent(doc = "The user seeked using the seekbar")
+ ACTION_SEEK(1027),
+
+ @UiEvent(doc = "The user opened the output switcher from a media control")
+ OPEN_OUTPUT_SWITCHER(1028);
+
+ override fun getId() = metricId
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
index a9a8fd1c0e9d..8c1845ac1ae0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
@@ -131,7 +131,7 @@ class SeekBarViewModel @Inject constructor(
}
}
- lateinit var logSmartspaceClick: () -> Unit
+ lateinit var logSeek: () -> Unit
fun getEnabled() = _data.enabled
@@ -175,7 +175,7 @@ class SeekBarViewModel @Inject constructor(
scrubbing = false
checkPlaybackPosition()
} else {
- logSmartspaceClick()
+ logSeek()
controller?.transportControls?.seekTo(position)
// Invalidate the cached playbackState to avoid the thumb jumping back to the previous
// position.
diff --git a/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt b/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt
index f1058e28863a..fbd17d7a212e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt
@@ -13,6 +13,7 @@ import android.graphics.PixelFormat
import android.graphics.drawable.Drawable
import android.os.SystemClock
import androidx.annotation.VisibleForTesting
+import com.android.internal.graphics.ColorUtils
import com.android.systemui.animation.Interpolators
import kotlin.math.abs
import kotlin.math.cos
@@ -157,8 +158,7 @@ class SquigglyProgress : Drawable() {
}
override fun setAlpha(alpha: Int) {
- wavePaint.alpha = alpha
- linePaint.alpha = (DISABLED_ALPHA * (alpha / 255f)).toInt()
+ updateColors(wavePaint.color, alpha)
}
override fun getAlpha(): Int {
@@ -166,8 +166,7 @@ class SquigglyProgress : Drawable() {
}
override fun setTint(tintColor: Int) {
- wavePaint.color = tintColor
- linePaint.color = tintColor
+ updateColors(tintColor, alpha)
}
override fun onLevelChange(level: Int): Boolean {
@@ -178,7 +177,12 @@ class SquigglyProgress : Drawable() {
if (tint == null) {
return
}
- wavePaint.color = tint.defaultColor
- linePaint.color = tint.defaultColor
+ updateColors(tint.defaultColor, alpha)
+ }
+
+ private fun updateColors(tintColor: Int, alpha: Int) {
+ wavePaint.color = ColorUtils.setAlphaComponent(tintColor, alpha)
+ linePaint.color = ColorUtils.setAlphaComponent(tintColor,
+ (DISABLED_ALPHA * (alpha / 255f)).toInt())
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index f4fcf10e7bb4..0edadcc82a24 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -20,7 +20,6 @@ import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -231,15 +230,6 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
}
}
- private boolean isDeviceIncluded(List<MediaDevice> deviceList, MediaDevice targetDevice) {
- for (MediaDevice device : deviceList) {
- if (TextUtils.equals(device.getId(), targetDevice.getId())) {
- return true;
- }
- }
- return false;
- }
-
private void onItemClick(View view, MediaDevice device) {
if (mController.isTransferring()) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index df0c14b25c26..5c536d469212 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -46,6 +46,8 @@ import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
+import java.util.List;
+
/**
* Base adapter for media output dialog.
*/
@@ -94,7 +96,18 @@ public abstract class MediaOutputBaseAdapter extends
boolean isCurrentlyConnected(MediaDevice device) {
return TextUtils.equals(device.getId(),
- mController.getCurrentConnectedMediaDevice().getId());
+ mController.getCurrentConnectedMediaDevice().getId())
+ || (mController.getSelectedMediaDevice().size() == 1
+ && isDeviceIncluded(mController.getSelectedMediaDevice(), device));
+ }
+
+ boolean isDeviceIncluded(List<MediaDevice> deviceList, MediaDevice targetDevice) {
+ for (MediaDevice device : deviceList) {
+ if (TextUtils.equals(device.getId(), targetDevice.getId())) {
+ return true;
+ }
+ }
+ return false;
}
boolean isDragging() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index dcb1c7c4637c..bde772d95674 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -21,6 +21,7 @@ import static android.view.WindowInsets.Type.statusBars;
import android.app.WallpaperColors;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -35,6 +36,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
+import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -65,6 +67,8 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
private static final String TAG = "MediaOutputDialog";
private static final String EMPTY_TITLE = " ";
+ private static final String PREF_NAME = "MediaOutputDialog";
+ private static final String PREF_IS_LE_BROADCAST_FIRST_LAUNCH = "PrefIsLeBroadcastFirstLaunch";
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
private final RecyclerView.LayoutManager mLayoutManager;
@@ -252,6 +256,33 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
}
// Show when remote media session is available
mStopButton.setVisibility(getStopButtonVisibility());
+ if (isBroadcastSupported() && mMediaOutputController.isPlaying()) {
+ mStopButton.setText(R.string.media_output_broadcast);
+ mStopButton.setOnClickListener(v -> {
+ SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME,
+ Context.MODE_PRIVATE);
+
+ if (sharedPref != null
+ && sharedPref.getBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, true)) {
+ Log.d(TAG, "PREF_IS_LE_BROADCAST_FIRST_LAUNCH: true");
+
+ mMediaOutputController.launchLeBroadcastNotifyDialog(mDialogView,
+ mBroadcastSender,
+ MediaOutputController.BroadcastNotifyDialog.ACTION_FIRST_LAUNCH);
+ SharedPreferences.Editor editor = sharedPref.edit();
+ editor.putBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, false);
+ editor.apply();
+ } else {
+ mMediaOutputController.launchMediaOutputBroadcastDialog(mDialogView,
+ mBroadcastSender);
+ }
+ });
+ } else {
+ mStopButton.setOnClickListener(v -> {
+ mMediaOutputController.releaseSession();
+ dismiss();
+ });
+ }
}
private Drawable resizeDrawable(Drawable drawable, int size) {
@@ -284,6 +315,10 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
abstract int getStopButtonVisibility();
+ public boolean isBroadcastSupported() {
+ return false;
+ }
+
@Override
public void onMediaChanged() {
mMainThreadHandler.post(() -> refresh());
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
new file mode 100644
index 000000000000..494dae0532dc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2022 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.media.dialog;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.text.method.HideReturnsTransformationMethod;
+import android.text.method.PasswordTransformationMethod;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewStub;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.core.graphics.drawable.IconCompat;
+
+import com.android.settingslib.qrcode.QrCodeGenerator;
+import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastSender;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
+import com.google.zxing.WriterException;
+
+/**
+ * Dialog for media output broadcast.
+ */
+@SysUISingleton
+public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
+ private static final String TAG = "BroadcastDialog";
+
+ private ViewStub mBroadcastInfoArea;
+ private ImageView mBroadcastQrCodeView;
+ private ImageView mBroadcastNotify;
+ private TextView mBroadcastName;
+ private ImageView mBroadcastNameEdit;
+ private TextView mBroadcastCode;
+ private ImageView mBroadcastCodeEye;
+ private Boolean mIsPasswordHide = true;
+ private ImageView mBroadcastCodeEdit;
+ private Button mStopButton;
+
+ static final int METADATA_BROADCAST_NAME = 0;
+ static final int METADATA_BROADCAST_CODE = 1;
+
+ MediaOutputBroadcastDialog(Context context, boolean aboveStatusbar,
+ BroadcastSender broadcastSender, MediaOutputController mediaOutputController) {
+ super(context, broadcastSender, mediaOutputController);
+ mAdapter = new MediaOutputGroupAdapter(mMediaOutputController);
+ // TODO(b/226710953): Move the part to MediaOutputBaseDialog for every class
+ // that extends MediaOutputBaseDialog
+ if (!aboveStatusbar) {
+ getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ initBtQrCodeUI();
+ }
+
+ @Override
+ int getHeaderIconRes() {
+ return 0;
+ }
+
+ @Override
+ IconCompat getHeaderIcon() {
+ return mMediaOutputController.getHeaderIcon();
+ }
+
+ @Override
+ int getHeaderIconSize() {
+ return mContext.getResources().getDimensionPixelSize(
+ R.dimen.media_output_dialog_header_album_icon_size);
+ }
+
+ @Override
+ CharSequence getHeaderText() {
+ return mMediaOutputController.getHeaderTitle();
+ }
+
+ @Override
+ CharSequence getHeaderSubtitle() {
+ return mMediaOutputController.getHeaderSubTitle();
+ }
+
+ @Override
+ Drawable getAppSourceIcon() {
+ return mMediaOutputController.getAppSourceIcon();
+ }
+
+ @Override
+ int getStopButtonVisibility() {
+ return View.VISIBLE;
+ }
+
+ // TODO(b/222674827): To get the information from BluetoothLeBroadcastMetadata(Broadcast code)
+ // and BluetoothLeAudioContentMetadata(Program info) when start Broadcast is successful.
+ private String getBroadcastMetaDataInfo(int metaData) {
+ switch (metaData) {
+ case METADATA_BROADCAST_NAME:
+ return "";
+ case METADATA_BROADCAST_CODE:
+ return "";
+ default:
+ return "";
+ }
+ }
+
+ private void initBtQrCodeUI() {
+ //add the view to xml
+ inflateBroadcastInfoArea();
+
+ //init UI component
+ mBroadcastQrCodeView = getDialogView().requireViewById(R.id.qrcode_view);
+ //Set the QR code view
+ setQrCodeView();
+
+ mBroadcastNotify = getDialogView().requireViewById(R.id.broadcast_info);
+ mBroadcastNotify.setOnClickListener(v -> {
+ mMediaOutputController.launchLeBroadcastNotifyDialog(null, null,
+ MediaOutputController.BroadcastNotifyDialog.ACTION_BROADCAST_INFO_ICON);
+ });
+ mBroadcastName = getDialogView().requireViewById(R.id.broadcast_name_summary);
+ mBroadcastNameEdit = getDialogView().requireViewById(R.id.broadcast_name_edit);
+ mBroadcastNameEdit.setOnClickListener(v -> {
+ launchBroadcastUpdatedDialog(false, mBroadcastName.getText().toString());
+ });
+ mBroadcastCode = getDialogView().requireViewById(R.id.broadcast_code_summary);
+ mBroadcastCode.setTransformationMethod(PasswordTransformationMethod.getInstance());
+ mBroadcastCodeEye = getDialogView().requireViewById(R.id.broadcast_code_eye);
+ mBroadcastCodeEye.setOnClickListener(v -> {
+ updateBroadcastCodeVisibility();
+ });
+ mBroadcastCodeEdit = getDialogView().requireViewById(R.id.broadcast_code_edit);
+ mBroadcastCodeEdit.setOnClickListener(v -> {
+ launchBroadcastUpdatedDialog(true, mBroadcastCode.getText().toString());
+ });
+
+ mBroadcastName.setText(getBroadcastMetaDataInfo(METADATA_BROADCAST_NAME));
+ mBroadcastCode.setText(getBroadcastMetaDataInfo(METADATA_BROADCAST_CODE));
+
+ mStopButton = getDialogView().requireViewById(R.id.stop);
+ mStopButton.setOnClickListener(v -> {
+ stopBroadcast();
+ });
+ }
+
+ private void inflateBroadcastInfoArea() {
+ mBroadcastInfoArea = getDialogView().requireViewById(R.id.broadcast_qrcode);
+ mBroadcastInfoArea.inflate();
+ }
+
+ private void setQrCodeView() {
+ //get the MetaData, and convert to BT QR code format.
+ String broadcastMetaData = getBroadcastMetaData();
+ if (broadcastMetaData.isEmpty()) {
+ //TDOD(b/226708424) Error handling for unable to generate the QR code bitmap
+ return;
+ }
+ try {
+ final int qrcodeSize = getContext().getResources().getDimensionPixelSize(
+ R.dimen.media_output_qrcode_size);
+ final Bitmap bmp = QrCodeGenerator.encodeQrCode(broadcastMetaData, qrcodeSize);
+ mBroadcastQrCodeView.setImageBitmap(bmp);
+ } catch (WriterException e) {
+ //TDOD(b/226708424) Error handling for unable to generate the QR code bitmap
+ Log.e(TAG, "Error generatirng QR code bitmap " + e);
+ }
+ }
+
+ private void updateBroadcastCodeVisibility() {
+ mBroadcastCode.setTransformationMethod(
+ mIsPasswordHide ? HideReturnsTransformationMethod.getInstance()
+ : PasswordTransformationMethod.getInstance());
+ mIsPasswordHide = !mIsPasswordHide;
+ }
+
+ private void launchBroadcastUpdatedDialog(boolean isPassword, String editString) {
+ final View layout = LayoutInflater.from(mContext).inflate(
+ R.layout.media_output_broadcast_update_dialog, null);
+ final EditText editText = layout.requireViewById(R.id.broadcast_edit_text);
+ editText.setText(editString);
+ final AlertDialog alertDialog = new Builder(mContext)
+ .setTitle(isPassword ? R.string.media_output_broadcast_code
+ : R.string.media_output_broadcast_name)
+ .setView(layout)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(R.string.media_output_broadcast_dialog_save,
+ (d, w) -> {
+ updateBroadcast(isPassword, editText.getText().toString());
+ })
+ .create();
+
+ alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ SystemUIDialog.setShowForAllUsers(alertDialog, true);
+ SystemUIDialog.registerDismissListener(alertDialog);
+ alertDialog.show();
+ }
+
+ /**
+ * TODO(b/222674827): The method should be get the BluetoothLeBroadcastMetadata after
+ * starting the Broadcast session successfully. Then we will follow the BT QR code format
+ * that convert BluetoothLeBroadcastMetadata object to String format.
+ */
+ private String getBroadcastMetaData() {
+ return "TEST";
+ }
+
+ /**
+ * TODO(b/222676140): These method are about the LE Audio Broadcast API. The framework APIS
+ * will be wrapped in SettingsLib. And the UI will be executed through it.
+ */
+ private void updateBroadcast(boolean isPassword, String updatedString) {
+
+ }
+
+ /**
+ * TODO(b/222676140): These method are about the LE Audio Broadcast API. The framework APIS
+ * will be wrapped in SettingsLib. And the UI will be executed through it.
+ */
+ private void stopBroadcast() {
+ dismiss();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 1cc96c0fd0de..807f0f1bb0ba 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -18,6 +18,7 @@ package com.android.systemui.media.dialog;
import static android.provider.Settings.ACTION_BLUETOOTH_PAIRING_SETTINGS;
+import android.app.AlertDialog;
import android.app.Notification;
import android.app.WallpaperColors;
import android.content.Context;
@@ -46,6 +47,7 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
+import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -56,7 +58,9 @@ import androidx.mediarouter.media.MediaRouterParams;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.BluetoothUtils;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.media.BluetoothMediaDevice;
import com.android.settingslib.media.InfoMediaManager;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
@@ -64,11 +68,13 @@ import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.monet.ColorScheme;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
import java.util.ArrayList;
import java.util.Collection;
@@ -93,6 +99,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
private final String mPackageName;
private final Context mContext;
private final MediaSessionManager mMediaSessionManager;
+ private final LocalBluetoothManager mLocalBluetoothManager;
private final ActivityStarter mActivityStarter;
private final DialogLaunchAnimator mDialogLaunchAnimator;
private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
@@ -117,6 +124,11 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
private int mColorConnectedItemBackground;
private int mColorPositiveButtonText;
+ public enum BroadcastNotifyDialog {
+ ACTION_FIRST_LAUNCH,
+ ACTION_BROADCAST_INFO_ICON
+ }
+
@Inject
public MediaOutputController(@NonNull Context context, String packageName,
MediaSessionManager mediaSessionManager, LocalBluetoothManager
@@ -127,6 +139,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
mContext = context;
mPackageName = packageName;
mMediaSessionManager = mediaSessionManager;
+ mLocalBluetoothManager = lbm;
mActivityStarter = starter;
mNotifCollection = notifCollection;
InfoMediaManager imm = new InfoMediaManager(mContext, packageName, null, lbm);
@@ -628,6 +641,42 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
mActivityStarter.startActivity(launchIntent, true, controller);
}
+ void launchLeBroadcastNotifyDialog(View mediaOutputDialog, BroadcastSender broadcastSender,
+ BroadcastNotifyDialog action) {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+ switch (action) {
+ case ACTION_FIRST_LAUNCH:
+ builder.setTitle(R.string.media_output_first_broadcast_title);
+ builder.setMessage(R.string.media_output_first_notify_broadcast_message);
+ builder.setNegativeButton(android.R.string.cancel, null);
+ builder.setPositiveButton(R.string.media_output_broadcast,
+ (d, w) -> {
+ launchMediaOutputBroadcastDialog(mediaOutputDialog, broadcastSender);
+ });
+ break;
+ case ACTION_BROADCAST_INFO_ICON:
+ builder.setTitle(R.string.media_output_broadcast);
+ builder.setMessage(R.string.media_output_broadcasting_message);
+ builder.setPositiveButton(android.R.string.ok, null);
+ break;
+ }
+
+ final AlertDialog dialog = builder.create();
+ dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ SystemUIDialog.setShowForAllUsers(dialog, true);
+ SystemUIDialog.registerDismissListener(dialog);
+ dialog.show();
+ }
+
+ void launchMediaOutputBroadcastDialog(View mediaOutputDialog, BroadcastSender broadcastSender) {
+ MediaOutputController controller = new MediaOutputController(mContext, mPackageName,
+ mMediaSessionManager, mLocalBluetoothManager, mActivityStarter,
+ mNotifCollection, mDialogLaunchAnimator, Optional.of(mNearbyMediaDevicesManager));
+ MediaOutputBroadcastDialog dialog = new MediaOutputBroadcastDialog(mContext, true,
+ broadcastSender, controller);
+ mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog);
+ }
+
boolean isActiveRemoteDevice(@NonNull MediaDevice device) {
final List<String> features = device.getFeatures();
return (features.contains(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK)
@@ -636,6 +685,20 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
|| features.contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK));
}
+ boolean isBluetoothLeDevice(@NonNull MediaDevice device) {
+ if (device instanceof BluetoothMediaDevice) {
+ final CachedBluetoothDevice cachedDevice =
+ ((BluetoothMediaDevice) device).getCachedDevice();
+ boolean isConnectedLeAudioDevice =
+ (cachedDevice != null) ? cachedDevice.isConnectedLeAudioDevice() : false;
+ if (DEBUG) {
+ Log.d(TAG, "isConnectedLeAudioDevice=" + isConnectedLeAudioDevice);
+ }
+ return isConnectedLeAudioDevice;
+ }
+ return false;
+ }
+
private boolean isPlayBackInfoLocal() {
return mMediaController != null
&& mMediaController.getPlaybackInfo() != null
@@ -643,6 +706,19 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
== MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL;
}
+ boolean isPlaying() {
+ if (mMediaController == null) {
+ return false;
+ }
+
+ PlaybackState state = mMediaController.getPlaybackState();
+ if (state == null) {
+ return false;
+ }
+
+ return (state.getState() == PlaybackState.STATE_PLAYING);
+ }
+
boolean isVolumeControlEnabled(@NonNull MediaDevice device) {
return isPlayBackInfoLocal()
|| mLocalMediaManager.isMediaSessionAvailableForVolumeControl();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index 7834ec0fa17f..3cffd0266ac8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -27,6 +27,7 @@ import androidx.core.graphics.drawable.IconCompat;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
+import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.SysUISingleton;
@@ -87,8 +88,20 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
@Override
int getStopButtonVisibility() {
- return mMediaOutputController.isActiveRemoteDevice(
- mMediaOutputController.getCurrentConnectedMediaDevice()) ? View.VISIBLE : View.GONE;
+ boolean isActiveRemoteDevice = mMediaOutputController.isActiveRemoteDevice(
+ mMediaOutputController.getCurrentConnectedMediaDevice());
+ boolean isBroadCastSupported = isBroadcastSupported();
+
+ return (isActiveRemoteDevice || isBroadCastSupported) ? View.VISIBLE : View.GONE;
+ }
+
+ @Override
+ public boolean isBroadcastSupported() {
+ MediaDevice device = mMediaOutputController.getCurrentConnectedMediaDevice();
+ if (device == null) {
+ return false;
+ }
+ return mMediaOutputController.isBluetoothLeDevice(device);
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index ade86ae76db4..20d811932363 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -427,6 +427,15 @@ public class NavigationBarController implements
}
}
+ public boolean isOverviewEnabled(int displayId) {
+ final NavigationBarView navBarView = getNavigationBarView(displayId);
+ if (navBarView != null) {
+ return navBarView.isOverviewEnabled();
+ } else {
+ return mTaskbarDelegate.isOverviewEnabled();
+ }
+ }
+
/** @return {@link NavigationBar} on the default display. */
@Nullable
public NavigationBar getDefaultNavigationBar() {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 75a3df7cad0c..be147b9fd585 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -309,6 +309,10 @@ public class TaskbarDelegate implements CommandQueue.Callbacks,
.commitUpdate(mDisplayId);
}
+ boolean isOverviewEnabled() {
+ return (mSysUiState.getFlags() & View.STATUS_BAR_DISABLE_RECENT) == 0;
+ }
+
private void updateAssistantAvailability(boolean assistantAvailable) {
if (mOverviewProxyService.getProxy() == null) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index a1258df7a12c..03652412c129 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -480,7 +480,9 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
public void onMotionEvent(MotionEvent event) {
if (mBackAnimation != null) {
mBackAnimation.onBackMotion(
- event, mIsLeftPanel ? BackEvent.EDGE_LEFT : BackEvent.EDGE_RIGHT);
+ event,
+ event.getActionMasked(),
+ mIsLeftPanel ? BackEvent.EDGE_LEFT : BackEvent.EDGE_RIGHT);
}
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 369a552a934a..2435497193e4 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -120,7 +120,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
"PNW.autoSaverNoThanks";
private static final String ACTION_ENABLE_SEVERE_BATTERY_DIALOG = "PNW.enableSevereDialog";
-
+ private static final String EXTRA_SCHEDULED_BY_PERCENTAGE =
+ "extra_scheduled_by_percentage";
public static final String BATTERY_SAVER_SCHEDULE_SCREEN_INTENT_ACTION =
"com.android.settings.BATTERY_SAVER_SCHEDULE_SETTINGS";
@@ -264,6 +265,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
if (showSevereLowBatteryDialog()) {
mBroadcastSender.sendBroadcast(new Intent(ACTION_ENABLE_SEVERE_BATTERY_DIALOG)
.setPackage(mContext.getPackageName())
+ .putExtra(EXTRA_SCHEDULED_BY_PERCENTAGE, isScheduledByPercentage())
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND));
// Reset the state once dialog been enabled
@@ -271,7 +273,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
mPlaySound = false;
return;
}
- if (!showLowBatteryNotification()) {
+ if (isScheduledByPercentage()) {
return;
}
@@ -327,26 +329,19 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
}
/**
- * Disable low battery warning notification if battery saver schedule mode set as
- * "Based on percentage".
+ * Checking battery saver schedule mode is set as "Based on percentage" or not.
*
- * return {@code false} if scheduled by percentage.
+ * return {@code true} if scheduled by percentage.
*/
- private boolean showLowBatteryNotification() {
+ private boolean isScheduledByPercentage() {
final ContentResolver resolver = mContext.getContentResolver();
final int mode = Settings.Global.getInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE,
PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
- // Return true if battery saver schedule mode will not trigger by percentage.
- if (mode != PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE) {
- return true;
- }
-
- // Return true if battery saver mode trigger percentage is less than 0, which means it is
+ // Return false if battery saver mode trigger percentage is less than 0, which means it is
// set as "Based on routine" mode, otherwise it will be "Based on percentage" mode.
- final int threshold =
- Settings.Global.getInt(resolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
- return threshold <= 0;
+ return mode == PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE
+ && Settings.Global.getInt(resolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) > 0;
}
private void showAutoSaverSuggestionNotification() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 8d0494afbb89..b5e1c5ee1a3e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -26,6 +26,7 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Trace;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
@@ -38,6 +39,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.keyguard.BouncerPanelExpansionCalculator;
+import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.animation.ShadeInterpolation;
@@ -58,13 +60,16 @@ import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.util.LifecycleFragment;
import com.android.systemui.util.Utils;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Named;
public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Callbacks,
- StatusBarStateController.StateListener {
+ StatusBarStateController.StateListener, Dumpable {
private static final String TAG = "QS";
private static final boolean DEBUG = false;
private static final String EXTRA_EXPANDED = "expanded";
@@ -135,7 +140,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
*/
private boolean mAnimateNextQsUpdate;
- private DumpManager mDumpManager;
+ private final DumpManager mDumpManager;
/**
* Progress of pull down from the center of the lock screen.
@@ -256,15 +261,26 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
}
@Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mDumpManager.registerDumpable(getClass().getName(), this);
+ }
+
+ @Override
public void onDestroy() {
super.onDestroy();
mStatusBarStateController.removeCallback(this);
if (mListening) {
setListening(false);
}
- mQSCustomizerController.setQs(null);
+ if (mQSCustomizerController != null) {
+ mQSCustomizerController.setQs(null);
+ }
mScrollListener = null;
- mDumpManager.unregisterDumpable(mContainer.getClass().getName());
+ if (mContainer != null) {
+ mDumpManager.unregisterDumpable(mContainer.getClass().getName());
+ }
+ mDumpManager.unregisterDumpable(getClass().getName());
}
@Override
@@ -272,7 +288,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
super.onSaveInstanceState(outState);
outState.putBoolean(EXTRA_EXPANDED, mQsExpanded);
outState.putBoolean(EXTRA_LISTENING, mListening);
- mQSCustomizerController.saveInstanceState(outState);
+ if (mQSCustomizerController != null) {
+ mQSCustomizerController.saveInstanceState(outState);
+ }
if (mQsExpanded) {
mQSPanelController.getTileLayout().saveInstanceState(outState);
}
@@ -594,7 +612,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
} else if (progress > 0 && view.getVisibility() != View.VISIBLE) {
view.setVisibility((View.VISIBLE));
}
- float alpha = (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
+ float alpha = mQSPanelController.bouncerInTransit()
? BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(progress)
: ShadeInterpolation.getContentAlpha(progress);
view.setAlpha(alpha);
@@ -745,13 +763,32 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
@Override
public int getQsMinExpansionHeight() {
+ if (mInSplitShade) {
+ return getQsMinExpansionHeightForSplitShade();
+ }
return mHeader.getHeight();
}
+ /**
+ * Returns the min expansion height for split shade.
+ *
+ * On split shade, QS is always expanded and goes from the top of the screen to the bottom of
+ * the QS container.
+ */
+ private int getQsMinExpansionHeightForSplitShade() {
+ getView().getLocationOnScreen(mTemp);
+ int top = mTemp[1];
+ // We want to get the original top position, so we subtract any translation currently set.
+ int originalTop = (int) (top - getView().getTranslationY());
+ // On split shade the QS view doesn't start at the top of the screen, so we need to add the
+ // top margin.
+ return originalTop + getView().getHeight();
+ }
+
@Override
public void hideImmediately() {
getView().animate().cancel();
- getView().setY(-mHeader.getHeight());
+ getView().setY(-getQsMinExpansionHeight());
}
private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
@@ -787,4 +824,62 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
setKeyguardShowing(newState == StatusBarState.KEYGUARD);
updateShowCollapsedOnKeyguard();
}
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ IndentingPrintWriter indentingPw = new IndentingPrintWriter(pw, /* singleIndent= */ " ");
+ indentingPw.println("QSFragment:");
+ indentingPw.increaseIndent();
+ indentingPw.println("mQsBounds: " + mQsBounds);
+ indentingPw.println("mQsExpanded: " + mQsExpanded);
+ indentingPw.println("mHeaderAnimating: " + mHeaderAnimating);
+ indentingPw.println("mStackScrollerOverscrolling: " + mStackScrollerOverscrolling);
+ indentingPw.println("mListening: " + mListening);
+ indentingPw.println("mLayoutDirection: " + mLayoutDirection);
+ indentingPw.println("mLastQSExpansion: " + mLastQSExpansion);
+ indentingPw.println("mLastPanelFraction: " + mLastPanelFraction);
+ indentingPw.println("mSquishinessFraction: " + mSquishinessFraction);
+ indentingPw.println("mQsDisabled: " + mQsDisabled);
+ indentingPw.println("mTemp: " + Arrays.toString(mTemp));
+ indentingPw.println("mShowCollapsedOnKeyguard: " + mShowCollapsedOnKeyguard);
+ indentingPw.println("mLastKeyguardAndExpanded: " + mLastKeyguardAndExpanded);
+ indentingPw.println("mState: " + StatusBarState.toString(mState));
+ indentingPw.println("mTmpLocation: " + Arrays.toString(mTmpLocation));
+ indentingPw.println("mLastViewHeight: " + mLastViewHeight);
+ indentingPw.println("mLastHeaderTranslation: " + mLastHeaderTranslation);
+ indentingPw.println("mInSplitShade: " + mInSplitShade);
+ indentingPw.println("mTransitioningToFullShade: " + mTransitioningToFullShade);
+ indentingPw.println("mFullShadeProgress: " + mFullShadeProgress);
+ indentingPw.println("mOverScrolling: " + mOverScrolling);
+ indentingPw.println("isCustomizing: " + mQSCustomizerController.isCustomizing());
+ View view = getView();
+ if (view != null) {
+ indentingPw.println("top: " + view.getTop());
+ indentingPw.println("y: " + view.getY());
+ indentingPw.println("translationY: " + view.getTranslationY());
+ indentingPw.println("alpha: " + view.getAlpha());
+ indentingPw.println("height: " + view.getHeight());
+ indentingPw.println("measuredHeight: " + view.getMeasuredHeight());
+ indentingPw.println("clipBounds: " + view.getClipBounds());
+ } else {
+ indentingPw.println("getView(): null");
+ }
+ QuickStatusBarHeader header = mHeader;
+ if (header != null) {
+ indentingPw.println("headerHeight: " + header.getHeight());
+ indentingPw.println("Header visibility: " + visibilityToString(header.getVisibility()));
+ } else {
+ indentingPw.println("mHeader: null");
+ }
+ }
+
+ private static String visibilityToString(int visibility) {
+ if (visibility == View.VISIBLE) {
+ return "VISIBLE";
+ }
+ if (visibility == View.INVISIBLE) {
+ return "INVISIBLE";
+ }
+ return "GONE";
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index dd2929c9a67a..10d792098608 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -43,6 +43,7 @@ import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.brightness.BrightnessController;
import com.android.systemui.settings.brightness.BrightnessMirrorHandler;
import com.android.systemui.settings.brightness.BrightnessSliderController;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.tuner.TunerService;
@@ -65,6 +66,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
private final BrightnessSliderController mBrightnessSliderController;
private final BrightnessMirrorHandler mBrightnessMirrorHandler;
private final FeatureFlags mFeatureFlags;
+ private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private boolean mGridContentVisible = true;
@@ -101,7 +103,8 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory,
BrightnessSliderController.Factory brightnessSliderFactory,
- FalsingManager falsingManager, FeatureFlags featureFlags) {
+ FalsingManager falsingManager, FeatureFlags featureFlags,
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
metricsLogger, uiEventLogger, qsLogger, dumpManager);
mQSFgsManagerFooter = qsFgsManagerFooter;
@@ -117,6 +120,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
mBrightnessController = brightnessControllerFactory.create(mBrightnessSliderController);
mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController);
mFeatureFlags = featureFlags;
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
view.setUseNewFooter(featureFlags.isEnabled(Flags.NEW_FOOTER));
}
@@ -281,5 +285,14 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
void setPageMargin(int pageMargin) {
mView.setPageMargin(pageMargin);
}
+
+ /**
+ * Determines if bouncer expansion is between 0 and 1 non-inclusive.
+ *
+ * @return if bouncer is in transit
+ */
+ public boolean bouncerInTransit() {
+ return mStatusBarKeyguardViewManager.bouncerIsInTransit();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
index 5c1d332df7a7..86ef85824eb0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
@@ -73,7 +73,7 @@ class QSLogger @Inject constructor(
log(DEBUG, {
str1 = tileSpec
int1 = statusBarState
- str2 = StatusBarState.toShortString(statusBarState)
+ str2 = StatusBarState.toString(statusBarState)
str3 = toStateString(state)
}, {
"[$str1] Tile clicked. StatusBarState=$str2. TileState=$str3"
@@ -84,7 +84,7 @@ class QSLogger @Inject constructor(
log(DEBUG, {
str1 = tileSpec
int1 = statusBarState
- str2 = StatusBarState.toShortString(statusBarState)
+ str2 = StatusBarState.toString(statusBarState)
str3 = toStateString(state)
}, {
"[$str1] Tile long clicked. StatusBarState=$str2. TileState=$str3"
@@ -95,7 +95,7 @@ class QSLogger @Inject constructor(
log(DEBUG, {
str1 = tileSpec
int1 = statusBarState
- str2 = StatusBarState.toShortString(statusBarState)
+ str2 = StatusBarState.toString(statusBarState)
str3 = toStateString(state)
}, {
"[$str1] Tile long clicked. StatusBarState=$str2. TileState=$str3"
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 15ad7798b3a3..c272602e3387 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -271,10 +271,8 @@ public class ScreenPinningRequest implements View.OnClickListener,
final Optional<CentralSurfaces> centralSurfacesOptional =
mCentralSurfacesOptionalLazy.get();
- NavigationBarView navigationBarView =
- centralSurfacesOptional.map(CentralSurfaces::getNavigationBarView).orElse(null);
- final boolean recentsVisible = navigationBarView != null
- && navigationBarView.isRecentsButtonVisible();
+ boolean recentsVisible =
+ centralSurfacesOptional.map(CentralSurfaces::isOverviewEnabled).orElse(false);
boolean touchExplorationEnabled = mAccessibilityService.isTouchExplorationEnabled();
int descriptionStringResId;
if (QuickStepContract.isGesturalMode(mNavBarMode)) {
@@ -295,6 +293,8 @@ public class ScreenPinningRequest implements View.OnClickListener,
: R.string.screen_pinning_description_recents_invisible;
}
+ NavigationBarView navigationBarView =
+ centralSurfacesOptional.map(CentralSurfaces::getNavigationBarView).orElse(null);
if (navigationBarView != null) {
((ImageView) mLayout.findViewById(R.id.screen_pinning_back_icon))
.setImageDrawable(navigationBarView.getBackDrawable());
diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java b/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java
index cc5cf4b63f99..d543eb2d647a 100644
--- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java
@@ -20,6 +20,11 @@ import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
import static android.hardware.SensorPrivacyManager.Sources.OTHER;
+import android.annotation.DimenRes;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
import android.hardware.SensorPrivacyManager;
import android.os.Bundle;
import android.util.Log;
@@ -28,6 +33,7 @@ import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
+import android.widget.Toast;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
@@ -36,18 +42,29 @@ import com.android.systemui.tv.TvBottomSheetActivity;
import javax.inject.Inject;
/**
- * Bottom sheet that is shown when the camera/mic sensors are blocked by the global toggle and
- * allows the user to re-enable them.
+ * Bottom sheet that is shown when the camera/mic sensors are blocked by the global software toggle
+ * or physical privacy switch.
*/
public class TvUnblockSensorActivity extends TvBottomSheetActivity {
private static final String TAG = TvUnblockSensorActivity.class.getSimpleName();
+ private static final String ACTION_MANAGE_CAMERA_PRIVACY =
+ "android.settings.MANAGE_CAMERA_PRIVACY";
+ private static final String ACTION_MANAGE_MICROPHONE_PRIVACY =
+ "android.settings.MANAGE_MICROPHONE_PRIVACY";
private static final int ALL_SENSORS = Integer.MAX_VALUE;
+
private int mSensor = -1;
private final IndividualSensorPrivacyController mSensorPrivacyController;
private IndividualSensorPrivacyController.Callback mSensorPrivacyCallback;
+ private TextView mTitle;
+ private TextView mContent;
+ private ImageView mIcon;
+ private ImageView mSecondIcon;
+ private Button mPositiveButton;
+ private Button mCancelButton;
@Inject
public TvUnblockSensorActivity(
@@ -76,52 +93,145 @@ public class TvUnblockSensorActivity extends TvBottomSheetActivity {
}
mSensorPrivacyCallback = (sensor, blocked) -> {
- if (mSensor == ALL_SENSORS) {
- if (!mSensorPrivacyController.isSensorBlocked(CAMERA)
- && !mSensorPrivacyController.isSensorBlocked(MICROPHONE)) {
- finish();
- }
+ if (mSensor == ALL_SENSORS && !mSensorPrivacyController.isSensorBlocked(CAMERA)
+ && !mSensorPrivacyController.isSensorBlocked(MICROPHONE)) {
+ showToastAndFinish();
} else if (this.mSensor == sensor && !blocked) {
- finish();
+ showToastAndFinish();
+ } else {
+ updateUI();
}
};
initUI();
}
+ private void showToastAndFinish() {
+ final int toastMsgResId;
+ switch(mSensor) {
+ case MICROPHONE:
+ toastMsgResId = R.string.sensor_privacy_mic_unblocked_toast_content;
+ break;
+ case CAMERA:
+ toastMsgResId = R.string.sensor_privacy_camera_unblocked_toast_content;
+ break;
+ case ALL_SENSORS:
+ default:
+ toastMsgResId = R.string.sensor_privacy_mic_camera_unblocked_toast_content;
+ break;
+ }
+ Toast.makeText(this, toastMsgResId, Toast.LENGTH_SHORT).show();
+ finish();
+ }
+
+ private boolean isBlockedByHardwareToggle() {
+ if (mSensor == ALL_SENSORS) {
+ return mSensorPrivacyController.isSensorBlockedByHardwareToggle(CAMERA)
+ || mSensorPrivacyController.isSensorBlockedByHardwareToggle(MICROPHONE);
+ } else {
+ return mSensorPrivacyController.isSensorBlockedByHardwareToggle(mSensor);
+ }
+ }
+
private void initUI() {
- TextView title = findViewById(R.id.bottom_sheet_title);
- TextView content = findViewById(R.id.bottom_sheet_body);
- ImageView icon = findViewById(R.id.bottom_sheet_icon);
+ mTitle = findViewById(R.id.bottom_sheet_title);
+ mContent = findViewById(R.id.bottom_sheet_body);
+ mIcon = findViewById(R.id.bottom_sheet_icon);
// mic icon if both icons are shown
- ImageView secondIcon = findViewById(R.id.bottom_sheet_second_icon);
- Button unblockButton = findViewById(R.id.bottom_sheet_positive_button);
- Button cancelButton = findViewById(R.id.bottom_sheet_negative_button);
+ mSecondIcon = findViewById(R.id.bottom_sheet_second_icon);
+ mPositiveButton = findViewById(R.id.bottom_sheet_positive_button);
+ mCancelButton = findViewById(R.id.bottom_sheet_negative_button);
+
+ mCancelButton.setText(android.R.string.cancel);
+ mCancelButton.setOnClickListener(v -> finish());
+
+ updateUI();
+ }
+
+ private void updateUI() {
+ if (isBlockedByHardwareToggle()) {
+ updateUiForHardwareToggle();
+ } else {
+ updateUiForSoftwareToggle();
+ }
+ }
+
+ private void updateUiForHardwareToggle() {
+ final Resources resources = getResources();
+
+ boolean micBlocked = (mSensor == MICROPHONE || mSensor == ALL_SENSORS)
+ && mSensorPrivacyController.isSensorBlockedByHardwareToggle(MICROPHONE);
+ boolean cameraBlocked = (mSensor == CAMERA || mSensor == ALL_SENSORS)
+ && mSensorPrivacyController.isSensorBlockedByHardwareToggle(CAMERA);
+
+ setIconTint(resources.getBoolean(R.bool.config_unblockHwSensorIconEnableTint));
+ setIconSize(R.dimen.unblock_hw_sensor_icon_width, R.dimen.unblock_hw_sensor_icon_height);
+
+ if (micBlocked && cameraBlocked) {
+ mTitle.setText(R.string.sensor_privacy_start_use_mic_camera_blocked_dialog_title);
+ mContent.setText(
+ R.string.sensor_privacy_start_use_mic_camera_blocked_dialog_content);
+ mIcon.setImageResource(R.drawable.unblock_hw_sensor_all);
+
+ Drawable secondIconDrawable = resources.getDrawable(
+ R.drawable.unblock_hw_sensor_all_second, getTheme());
+ if (secondIconDrawable == null) {
+ mSecondIcon.setVisibility(View.GONE);
+ } else {
+ mSecondIcon.setImageDrawable(secondIconDrawable);
+ }
+ } else if (cameraBlocked) {
+ mTitle.setText(R.string.sensor_privacy_start_use_camera_blocked_dialog_title);
+ mContent.setText(R.string.sensor_privacy_start_use_camera_blocked_dialog_content);
+ mIcon.setImageResource(R.drawable.unblock_hw_sensor_camera);
+ mSecondIcon.setVisibility(View.GONE);
+ } else if (micBlocked) {
+ mTitle.setText(R.string.sensor_privacy_start_use_mic_blocked_dialog_title);
+ mContent.setText(R.string.sensor_privacy_start_use_mic_blocked_dialog_content);
+ mIcon.setImageResource(R.drawable.unblock_hw_sensor_microphone);
+ mSecondIcon.setVisibility(View.GONE);
+ }
+
+ // Start animation if drawable is animated
+ Drawable iconDrawable = mIcon.getDrawable();
+ if (iconDrawable instanceof Animatable) {
+ ((Animatable) iconDrawable).start();
+ }
+
+ mPositiveButton.setVisibility(View.GONE);
+ mCancelButton.setText(android.R.string.ok);
+ }
+
+ private void updateUiForSoftwareToggle() {
+ setIconTint(true);
+ setIconSize(R.dimen.bottom_sheet_icon_size, R.dimen.bottom_sheet_icon_size);
switch (mSensor) {
case MICROPHONE:
- title.setText(R.string.sensor_privacy_start_use_mic_dialog_title);
- content.setText(R.string.sensor_privacy_start_use_mic_dialog_content);
- icon.setImageResource(com.android.internal.R.drawable.perm_group_microphone);
- secondIcon.setVisibility(View.GONE);
+ mTitle.setText(R.string.sensor_privacy_start_use_mic_dialog_title);
+ mContent.setText(R.string.sensor_privacy_start_use_mic_dialog_content);
+ mIcon.setImageResource(com.android.internal.R.drawable.perm_group_microphone);
+ mSecondIcon.setVisibility(View.GONE);
break;
case CAMERA:
- title.setText(R.string.sensor_privacy_start_use_camera_dialog_title);
- content.setText(R.string.sensor_privacy_start_use_camera_dialog_content);
- icon.setImageResource(com.android.internal.R.drawable.perm_group_camera);
- secondIcon.setVisibility(View.GONE);
+ mTitle.setText(R.string.sensor_privacy_start_use_camera_dialog_title);
+ mContent.setText(R.string.sensor_privacy_start_use_camera_dialog_content);
+ mIcon.setImageResource(com.android.internal.R.drawable.perm_group_camera);
+ mSecondIcon.setVisibility(View.GONE);
break;
case ALL_SENSORS:
default:
- title.setText(R.string.sensor_privacy_start_use_mic_camera_dialog_title);
- content.setText(R.string.sensor_privacy_start_use_mic_camera_dialog_content);
- icon.setImageResource(com.android.internal.R.drawable.perm_group_camera);
- secondIcon.setImageResource(com.android.internal.R.drawable.perm_group_microphone);
+ mTitle.setText(R.string.sensor_privacy_start_use_mic_camera_dialog_title);
+ mContent.setText(R.string.sensor_privacy_start_use_mic_camera_dialog_content);
+ mIcon.setImageResource(com.android.internal.R.drawable.perm_group_camera);
+ mSecondIcon.setImageResource(
+ com.android.internal.R.drawable.perm_group_microphone);
break;
}
- unblockButton.setText(
+
+ mPositiveButton.setText(
com.android.internal.R.string.sensor_privacy_start_use_dialog_turn_on_button);
- unblockButton.setOnClickListener(v -> {
+ mPositiveButton.setOnClickListener(v -> {
if (mSensor == ALL_SENSORS) {
mSensorPrivacyController.setSensorBlocked(OTHER, CAMERA, false);
mSensorPrivacyController.setSensorBlocked(OTHER, MICROPHONE, false);
@@ -129,14 +239,43 @@ public class TvUnblockSensorActivity extends TvBottomSheetActivity {
mSensorPrivacyController.setSensorBlocked(OTHER, mSensor, false);
}
});
+ }
+
+ private void setIconTint(boolean enableTint) {
+ final Resources resources = getResources();
+
+ if (enableTint) {
+ final ColorStateList iconTint = resources.getColorStateList(
+ R.color.bottom_sheet_icon_color, getTheme());
+ mIcon.setImageTintList(iconTint);
+ mSecondIcon.setImageTintList(iconTint);
+ } else {
+ mIcon.setImageTintList(null);
+ mSecondIcon.setImageTintList(null);
+ }
+
+ mIcon.invalidate();
+ mSecondIcon.invalidate();
+ }
+
+ private void setIconSize(@DimenRes int widthRes, @DimenRes int heightRes) {
+ final Resources resources = getResources();
+ final int iconWidth = resources.getDimensionPixelSize(widthRes);
+ final int iconHeight = resources.getDimensionPixelSize(heightRes);
+
+ mIcon.getLayoutParams().width = iconWidth;
+ mIcon.getLayoutParams().height = iconHeight;
+ mIcon.invalidate();
- cancelButton.setText(android.R.string.cancel);
- cancelButton.setOnClickListener(v -> finish());
+ mSecondIcon.getLayoutParams().width = iconWidth;
+ mSecondIcon.getLayoutParams().height = iconHeight;
+ mSecondIcon.invalidate();
}
@Override
public void onResume() {
super.onResume();
+ updateUI();
mSensorPrivacyController.addCallback(mSensorPrivacyCallback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
index 16bc951e0323..718bc5caf414 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
@@ -37,16 +37,19 @@ public class StatusBarState {
*/
public static final int SHADE_LOCKED = 2;
- public static String toShortString(int x) {
- switch (x) {
+ /**
+ * Returns the textual representation of the status bar state.
+ */
+ public static String toString(int state) {
+ switch (state) {
case SHADE:
- return "SHD";
+ return "SHADE";
case SHADE_LOCKED:
- return "SHD_LCK";
+ return "SHADE_LOCKED";
case KEYGUARD:
- return "KGRD";
+ return "KEYGUARD";
default:
- return "bad_value_" + x;
+ return "UNKNOWN: " + state;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 2763bd711338..93103e2c3f49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -174,10 +174,21 @@ public class StatusBarStateControllerImpl implements
if (state > MAX_STATE || state < MIN_STATE) {
throw new IllegalArgumentException("Invalid state " + state);
}
- if (!force && state == mState) {
+
+ // Unless we're explicitly asked to force the state change, don't apply the new state if
+ // it's identical to both the current and upcoming states, since that should not be
+ // necessary.
+ if (!force && state == mState && state == mUpcomingState) {
return false;
}
+ if (state != mUpcomingState) {
+ Log.d(TAG, "setState: requested state " + StatusBarState.toString(state)
+ + "!= upcomingState: " + StatusBarState.toString(mUpcomingState) + ". "
+ + "This usually means the status bar state transition was interrupted before "
+ + "the upcoming state could be applied.");
+ }
+
// Record the to-be mState and mLastState
recordHistoricalState(state /* newState */, mState /* lastState */, false);
@@ -508,7 +519,7 @@ public class StatusBarStateControllerImpl implements
* Returns String readable state of status bar from {@link StatusBarState}
*/
public static String describe(int state) {
- return StatusBarState.toShortString(state);
+ return StatusBarState.toString(state);
}
@Override
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 32d37d18f407..c0553b5c3c2d 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
@@ -347,7 +347,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
setDimAmount((Float) animation.getAnimatedValue());
}
};
- protected ViewGroup mQsContainer;
+ protected ViewGroup mQsHeader;
+ // Rect of QsHeader. Kept as a field just to avoid creating a new one each time.
+ private Rect mQsHeaderBound = new Rect();
private boolean mContinuousShadowUpdate;
private boolean mContinuousBackgroundUpdate;
private ViewTreeObserver.OnPreDrawListener mShadowUpdater
@@ -1598,8 +1600,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.ADAPTER)
- public void setQsContainer(ViewGroup qsContainer) {
- mQsContainer = qsContainer;
+ public void setQsHeader(ViewGroup qsHeader) {
+ mQsHeader = qsHeader;
}
@ShadeViewRefactor(RefactorComponent.ADAPTER)
@@ -3458,7 +3460,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
if (!isScrollingEnabled()) {
return false;
}
- if (isInsideQsContainer(ev) && !mIsBeingDragged) {
+ if (isInsideQsHeader(ev) && !mIsBeingDragged) {
return false;
}
mForcedScroll = null;
@@ -3611,8 +3613,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- protected boolean isInsideQsContainer(MotionEvent ev) {
- return ev.getY() < mQsContainer.getBottom();
+ protected boolean isInsideQsHeader(MotionEvent ev) {
+ mQsHeader.getBoundsOnScreen(mQsHeaderBound);
+ return mQsHeaderBound.contains((int) ev.getX(), (int) ev.getY());
}
@ShadeViewRefactor(RefactorComponent.INPUT)
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 5bc50ae11fb7..3e630cdf8f97 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
@@ -1234,8 +1234,9 @@ public class NotificationStackScrollLayoutController {
mView.setExpandedHeight(expandedHeight);
}
- public void setQsContainer(ViewGroup view) {
- mView.setQsContainer(view);
+ /** Sets the QS header. Used to check if a touch is within its bounds. */
+ public void setQsHeader(ViewGroup view) {
+ mView.setQsHeader(view);
}
public void setAnimationsEnabled(boolean enabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 6f6ce28ed6b3..ffe4d4f11819 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -3436,6 +3436,10 @@ public class CentralSurfaces extends CoreStartable implements
return mNavigationBarController.getNavigationBarView(mDisplayId);
}
+ public boolean isOverviewEnabled() {
+ return mNavigationBarController.isOverviewEnabled(mDisplayId);
+ }
+
public void showPinningEnterExitToast(boolean entering) {
mNavigationBarController.showPinningEnterExitToast(mDisplayId, entering);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 8b25c2bc20b9..ebe91c7dc5d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -292,11 +292,20 @@ public class DozeParameters implements
}
public void updateControlScreenOff() {
- if (!getDisplayNeedsBlanking()) {
- final boolean controlScreenOff =
- getAlwaysOn() && (mKeyguardShowing || shouldControlUnlockedScreenOff());
- setControlScreenOffAnimation(controlScreenOff);
- }
+ final boolean controlScreenOff = shouldControlUnlockedScreenOff()
+ || (!getDisplayNeedsBlanking() && getAlwaysOn() && mKeyguardShowing);
+ setControlScreenOffAnimation(controlScreenOff);
+ }
+
+ /**
+ * Whether we're capable of controlling the screen off animation if we want to. This isn't
+ * possible if AOD isn't even enabled or if the flag is disabled, or if the display needs
+ * blanking.
+ */
+ public boolean canControlUnlockedScreenOff() {
+ return getAlwaysOn()
+ && mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)
+ && !getDisplayNeedsBlanking();
}
/**
@@ -309,8 +318,7 @@ public class DozeParameters implements
* disabled for a11y.
*/
public boolean shouldControlUnlockedScreenOff() {
- return canControlUnlockedScreenOff()
- && mUnlockedScreenOffAnimationController.shouldPlayUnlockedScreenOffAnimation();
+ return mUnlockedScreenOffAnimationController.shouldPlayUnlockedScreenOffAnimation();
}
public boolean shouldDelayKeyguardShow() {
@@ -342,16 +350,6 @@ public class DozeParameters implements
return getAlwaysOn() && mKeyguardShowing;
}
- /**
- * Whether we're capable of controlling the screen off animation if we want to. This isn't
- * possible if AOD isn't even enabled or if the flag is disabled.
- */
- public boolean canControlUnlockedScreenOff() {
- return getAlwaysOn()
- && mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)
- && !getDisplayNeedsBlanking();
- }
-
private boolean getBoolean(String propName, int resId) {
return SystemProperties.getBoolean(propName, mResources.getBoolean(resId));
}
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 2d16b52839eb..11628cb75e87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -3592,7 +3592,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
});
mLockscreenShadeTransitionController.setQS(mQs);
- mNotificationStackScrollLayoutController.setQsContainer((ViewGroup) mQs.getView());
+ mNotificationStackScrollLayoutController.setQsHeader((ViewGroup) mQs.getHeader());
mQs.setScrollListener(mScrollListener);
updateQsExpansion();
}
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 be50a17b8536..71f199f330a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -797,10 +797,9 @@ public abstract class PanelViewController {
}
mExpandedFraction = Math.min(1f,
maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
- mAmbientState.setExpansionFraction(mKeyguardStateController.isUnlocked()
- ? mExpandedFraction
- : BouncerPanelExpansionCalculator
- .getBackScrimScaledExpansion(mExpandedFraction));
+ mAmbientState.setExpansionFraction(mStatusBarKeyguardViewManager.bouncerIsInTransit()
+ ? BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(mExpandedFraction)
+ : mExpandedFraction);
onHeightUpdated(mExpandedHeight);
updatePanelExpansionAndVisibility();
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 8272ed926255..0b95458b73df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -204,6 +204,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private final Executor mMainExecutor;
private final ScreenOffAnimationController mScreenOffAnimationController;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private GradientColors mColors;
private boolean mNeedsDrawableColorUpdate;
@@ -266,7 +267,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
ConfigurationController configurationController, @Main Executor mainExecutor,
ScreenOffAnimationController screenOffAnimationController,
PanelExpansionStateManager panelExpansionStateManager,
- KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
+ KeyguardUnlockAnimationController keyguardUnlockAnimationController,
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
mScrimStateListener = lightBarController::setScrimState;
mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
@@ -292,6 +294,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
keyguardStateController.getKeyguardFadingAwayDuration());
}
});
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
@Override
public void onThemeChanged() {
@@ -855,6 +858,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
// We're unoccluding the keyguard and don't want to have a bright flash.
mNotificationsAlpha = ScrimState.KEYGUARD.getNotifAlpha();
mNotificationsTint = ScrimState.KEYGUARD.getNotifTint();
+ mBehindAlpha = ScrimState.KEYGUARD.getBehindAlpha();
+ mBehindTint = ScrimState.KEYGUARD.getBehindTint();
}
}
if (mState != ScrimState.UNLOCKED) {
@@ -1021,6 +1026,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
if (aodWallpaperTimeout || occludedKeyguard) {
mBehindAlpha = 1;
}
+ // Prevent notification scrim flicker when transitioning away from keyguard.
+ if (mKeyguardStateController.isKeyguardGoingAway()) {
+ mNotificationsAlpha = 0;
+ }
setScrimAlpha(mScrimInFront, mInFrontAlpha);
setScrimAlpha(mScrimBehind, mBehindAlpha);
setScrimAlpha(mNotificationsScrim, mNotificationsAlpha);
@@ -1057,7 +1066,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
private float getInterpolatedFraction() {
- if (mState == ScrimState.KEYGUARD || mState == ScrimState.SHADE_LOCKED) {
+ if (mStatusBarKeyguardViewManager.bouncerIsInTransit()) {
return BouncerPanelExpansionCalculator
.getBackScrimScaledExpansion(mPanelExpansionFraction);
}
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 23401618e1f3..a1cbba47e822 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -1368,6 +1368,15 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
/**
+ * Returns if bouncer expansion is between 0 and 1 non-inclusive.
+ */
+ public boolean bouncerIsInTransit() {
+ if (mBouncer == null) return false;
+
+ return mBouncer.inTransit();
+ }
+
+ /**
* Delegate used to send show/reset events to an alternate authentication method instead of the
* regular pin/pattern/password bouncer.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index c11d450e47b2..ea935be334c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -59,8 +59,14 @@ class UnlockedScreenOffAnimationController @Inject constructor(
private val powerManager: PowerManager,
private val handler: Handler = Handler()
) : WakefulnessLifecycle.Observer, ScreenOffAnimation {
-
private lateinit var mCentralSurfaces: CentralSurfaces
+ /**
+ * Whether or not [initialize] has been called to provide us with the StatusBar,
+ * NotificationPanelViewController, and LightRevealSrim so that we can run the unlocked screen
+ * off animation.
+ */
+ private var initialized = false
+
private lateinit var lightRevealScrim: LightRevealScrim
private var animatorDurationScale = 1f
@@ -116,6 +122,7 @@ class UnlockedScreenOffAnimationController @Inject constructor(
centralSurfaces: CentralSurfaces,
lightRevealScrim: LightRevealScrim
) {
+ this.initialized = true
this.lightRevealScrim = lightRevealScrim
this.mCentralSurfaces = centralSurfaces
@@ -262,6 +269,18 @@ class UnlockedScreenOffAnimationController @Inject constructor(
* on the current state of the device.
*/
fun shouldPlayUnlockedScreenOffAnimation(): Boolean {
+ // If we haven't been initialized yet, we don't have a StatusBar/LightRevealScrim yet, so we
+ // can't perform the animation.
+ if (!initialized) {
+ return false
+ }
+
+ // If the device isn't in a state where we can control unlocked screen off (no AOD enabled,
+ // power save, etc.) then we shouldn't try to do so.
+ if (!dozeParameters.get().canControlUnlockedScreenOff()) {
+ return false
+ }
+
// If we explicitly already decided not to play the screen off animation, then never change
// our mind.
if (decidedToAnimateGoingToSleep == false) {
@@ -304,7 +323,7 @@ class UnlockedScreenOffAnimationController @Inject constructor(
}
override fun shouldDelayDisplayDozeTransition(): Boolean =
- dozeParameters.get().shouldControlUnlockedScreenOff()
+ shouldPlayUnlockedScreenOffAnimation()
/**
* Whether we're doing the light reveal animation or we're done with that and animating in the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 6ee65ae7e2ef..ec44f18c8eb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -394,6 +394,7 @@ class OngoingCallController @Inject constructor(
override fun onUidActive(uid: Int) {}
override fun onUidIdle(uid: Int, disabled: Boolean) {}
override fun onUidCachedChanged(uid: Int, cached: Boolean) {}
+ override fun onUidProcAdjChanged(uid: Int) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
index e01b95e81da8..1e73d593c8de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
@@ -27,6 +27,12 @@ public interface IndividualSensorPrivacyController extends
boolean isSensorBlocked(@Sensor int sensor);
+ /**
+ * Returns {@code true} if the given sensor is blocked by a hardware toggle, {@code false}
+ * if the sensor is not blocked or blocked by a software toggle.
+ */
+ boolean isSensorBlockedByHardwareToggle(@Sensor int sensor);
+
void setSensorBlocked(@Source int source, @Sensor int sensor, boolean blocked);
void suppressSensorPrivacyReminders(int sensor, boolean suppress);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
index 1d71301c7454..e4c444da5da9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
@@ -22,6 +22,7 @@ import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
import android.hardware.SensorPrivacyManager;
import android.hardware.SensorPrivacyManager.Sensors.Sensor;
import android.hardware.SensorPrivacyManager.Sources.Source;
+import android.hardware.SensorPrivacyManager.ToggleType;
import android.util.ArraySet;
import android.util.SparseBooleanArray;
@@ -34,7 +35,8 @@ public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPr
private static final int[] SENSORS = new int[] {CAMERA, MICROPHONE};
private final @NonNull SensorPrivacyManager mSensorPrivacyManager;
- private final SparseBooleanArray mState = new SparseBooleanArray();
+ private final SparseBooleanArray mSoftwareToggleState = new SparseBooleanArray();
+ private final SparseBooleanArray mHardwareToggleState = new SparseBooleanArray();
private final Set<Callback> mCallbacks = new ArraySet<>();
public IndividualSensorPrivacyControllerImpl(
@@ -44,11 +46,27 @@ public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPr
@Override
public void init() {
- for (int sensor : SENSORS) {
- mSensorPrivacyManager.addSensorPrivacyListener(sensor,
- (s, enabled) -> onSensorPrivacyChanged(sensor, enabled));
+ mSensorPrivacyManager.addSensorPrivacyListener(
+ new SensorPrivacyManager.OnSensorPrivacyChangedListener() {
+ @Override
+ public void onSensorPrivacyChanged(SensorPrivacyChangedParams params) {
+ IndividualSensorPrivacyControllerImpl.this.onSensorPrivacyChanged(
+ params.getSensor(), params.getToggleType(), params.isEnabled());
+ }
+
+ @Override
+ public void onSensorPrivacyChanged(int sensor, boolean enabled) {
+ // handled in onSensorPrivacyChanged(SensorPrivacyChangedParams)
+ }
+ });
- mState.put(sensor, mSensorPrivacyManager.isSensorPrivacyEnabled(sensor));
+ for (int sensor : SENSORS) {
+ boolean softwarePrivacyEnabled = mSensorPrivacyManager.isSensorPrivacyEnabled(
+ SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE, sensor);
+ boolean hardwarePrivacyEnabled = mSensorPrivacyManager.isSensorPrivacyEnabled(
+ SensorPrivacyManager.TOGGLE_TYPE_HARDWARE, sensor);
+ mSoftwareToggleState.put(sensor, softwarePrivacyEnabled);
+ mHardwareToggleState.put(sensor, hardwarePrivacyEnabled);
}
}
@@ -59,7 +77,12 @@ public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPr
@Override
public boolean isSensorBlocked(@Sensor int sensor) {
- return mState.get(sensor, false);
+ return mSoftwareToggleState.get(sensor, false) || mHardwareToggleState.get(sensor, false);
+ }
+
+ @Override
+ public boolean isSensorBlockedByHardwareToggle(@Sensor int sensor) {
+ return mHardwareToggleState.get(sensor, false);
}
@Override
@@ -82,11 +105,16 @@ public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPr
mCallbacks.remove(listener);
}
- private void onSensorPrivacyChanged(@Sensor int sensor, boolean blocked) {
- mState.put(sensor, blocked);
+ private void onSensorPrivacyChanged(@Sensor int sensor, @ToggleType int toggleType,
+ boolean enabled) {
+ if (toggleType == SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE) {
+ mSoftwareToggleState.put(sensor, enabled);
+ } else if (toggleType == SensorPrivacyManager.TOGGLE_TYPE_HARDWARE) {
+ mHardwareToggleState.put(sensor, enabled);
+ }
for (Callback callback : mCallbacks) {
- callback.onSensorBlockedChanged(sensor, blocked);
+ callback.onSensorBlockedChanged(sensor, isSensorBlocked(sensor));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index f52c6ed0a232..3e50acb75401 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -86,6 +86,7 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
private boolean mShouldDisplayAllAccesses;
private boolean mShowSystemAccessesFlag;
private boolean mShowSystemAccessesSetting;
+ private boolean mExperimentStarted;
@Inject
public LocationControllerImpl(Context context, AppOpsController appOpsController,
@@ -107,6 +108,9 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
mShouldDisplayAllAccesses = getAllAccessesSetting();
mShowSystemAccessesFlag = getShowSystemFlag();
mShowSystemAccessesSetting = getShowSystemSetting();
+ mExperimentStarted = getExperimentStarted();
+ toggleSystemSettingIfExperimentJustStarted();
+
mContentObserver = new ContentObserver(mBackgroundHandler) {
@Override
public void onChange(boolean selfChange) {
@@ -123,8 +127,15 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
DeviceConfig.NAMESPACE_PRIVACY,
backgroundHandler::post,
properties -> {
+ // Update the Device Config flag which controls the experiment to display
+ // location accesses.
mShouldDisplayAllAccesses = getAllAccessesSetting();
- mShowSystemAccessesFlag = getShowSystemSetting();
+ // Update the Device Config flag which controls the experiment to display
+ // system location accesses.
+ mShowSystemAccessesFlag = getShowSystemFlag();
+ // Update the local flag for the system accesses experiment and potentially
+ // update the behavior based on the flag value.
+ toggleSystemSettingIfExperimentJustStarted();
updateActiveLocationRequests();
});
@@ -222,6 +233,33 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
return mSecureSettings.getInt(Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 0) == 1;
}
+ private boolean getExperimentStarted() {
+ return mSecureSettings
+ .getInt(Settings.Secure.LOCATION_INDICATOR_EXPERIMENT_STARTED, 0) == 1;
+ }
+
+ private void toggleSystemSettingIfExperimentJustStarted() {
+ // mShowSystemAccessesFlag indicates whether the Device Config flag is flipped
+ // by an experiment. mExperimentStarted is the local device value which indicates the last
+ // value the device has seen for the Device Config flag.
+ // The local device value is needed to determine that the Device Config flag was just
+ // flipped, as the experiment behavior should only happen once after the experiment is
+ // enabled.
+ if (mShowSystemAccessesFlag && !mExperimentStarted) {
+ // If the Device Config flag is enabled, but the local device setting is not then the
+ // experiment just started. Update the local flag to match and enable the experiment
+ // behavior by flipping the show system setting value.
+ mSecureSettings.putInt(Settings.Secure.LOCATION_INDICATOR_EXPERIMENT_STARTED, 1);
+ mSecureSettings.putInt(Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 1);
+ mExperimentStarted = true;
+ } else if (!mShowSystemAccessesFlag && mExperimentStarted) {
+ // If the Device Config flag is disabled, but the local device flag is enabled then
+ // update the local device flag to match.
+ mSecureSettings.putInt(Settings.Secure.LOCATION_INDICATOR_EXPERIMENT_STARTED, 0);
+ mExperimentStarted = false;
+ }
+ }
+
/**
* Returns true if there currently exist active high power location requests.
*/
@@ -249,7 +287,6 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
}
boolean hadActiveLocationRequests = mAreActiveLocationRequests;
boolean shouldDisplay = false;
- boolean showSystem = mShowSystemAccessesFlag || mShowSystemAccessesSetting;
boolean systemAppOp = false;
boolean nonSystemAppOp = false;
boolean isSystemApp;
@@ -267,7 +304,7 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
nonSystemAppOp = true;
}
- shouldDisplay = showSystem || shouldDisplay || !isSystemApp;
+ shouldDisplay = mShowSystemAccessesSetting || shouldDisplay || !isSystemApp;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 8396639fe0f5..2c05a4ea8238 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -1155,7 +1155,8 @@ public class UserSwitcherController implements Dumpable {
setButton(DialogInterface.BUTTON_POSITIVE,
context.getString(mGuestUserAutoCreated
? com.android.settingslib.R.string.guest_reset_guest_confirm_button
- : R.string.guest_exit_guest_dialog_remove), this);
+ : com.android.settingslib.R.string.guest_remove_guest_confirm_button),
+ this);
SystemUIDialog.setWindowOnTop(this, mKeyguardStateController.isShowing());
setCanceledOnTouchOutside(false);
mGuestId = guestId;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 85a6eebf6bd7..e4c83a543d89 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -49,7 +49,6 @@ import android.os.VibrationEffect;
import android.provider.Settings;
import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
-import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
@@ -418,41 +417,8 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
}
private void onGetCaptionsComponentStateW(boolean fromTooltip) {
- if (mCaptioningManager.isSystemAudioCaptioningUiEnabled()) {
- mCallbacks.onCaptionComponentStateChanged(true, fromTooltip);
- return;
- }
-
- // TODO(b/220968335): Remove this check once system captions component migrates
- // to new CaptioningManager APIs.
- try {
- String componentNameString = mContext.getString(
- com.android.internal.R.string.config_defaultSystemCaptionsService);
- if (TextUtils.isEmpty(componentNameString)) {
- // component doesn't exist
- mCallbacks.onCaptionComponentStateChanged(false, fromTooltip);
- return;
- }
-
- if (D.BUG) {
- Log.i(TAG, String.format(
- "isCaptionsServiceEnabled componentNameString=%s", componentNameString));
- }
-
- ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
- if (componentName == null) {
- mCallbacks.onCaptionComponentStateChanged(false, fromTooltip);
- return;
- }
-
- mCallbacks.onCaptionComponentStateChanged(
- mPackageManager.getComponentEnabledSetting(componentName)
- == PackageManager.COMPONENT_ENABLED_STATE_ENABLED, fromTooltip);
- } catch (Exception ex) {
- Log.e(TAG,
- "isCaptionsServiceEnabled failed to check for captions component", ex);
- mCallbacks.onCaptionComponentStateChanged(false, fromTooltip);
- }
+ mCallbacks.onCaptionComponentStateChanged(
+ mCaptioningManager.isSystemAudioCaptioningUiEnabled(), fromTooltip);
}
private void onAccessibilityModeChanged(Boolean showA11yStream) {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 8a961942123b..4d34aa38b3cd 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -28,7 +28,6 @@ import static android.service.notification.NotificationListenerService.REASON_GR
import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -61,7 +60,6 @@ import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -81,6 +79,7 @@ import com.android.systemui.statusbar.notification.collection.render.Notificatio
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.wm.shell.bubbles.Bubble;
import com.android.wm.shell.bubbles.BubbleEntry;
@@ -132,7 +131,7 @@ public class BubblesManager implements Dumpable {
public static BubblesManager create(Context context,
Optional<Bubbles> bubblesOptional,
NotificationShadeWindowController notificationShadeWindowController,
- StatusBarStateController statusBarStateController,
+ KeyguardStateController keyguardStateController,
ShadeController shadeController,
ConfigurationController configurationController,
@Nullable IStatusBarService statusBarService,
@@ -150,13 +149,26 @@ public class BubblesManager implements Dumpable {
DumpManager dumpManager,
Executor sysuiMainExecutor) {
if (bubblesOptional.isPresent()) {
- return new BubblesManager(context, bubblesOptional.get(),
- notificationShadeWindowController, statusBarStateController, shadeController,
- configurationController, statusBarService, notificationManager,
+ return new BubblesManager(context,
+ bubblesOptional.get(),
+ notificationShadeWindowController,
+ keyguardStateController,
+ shadeController,
+ configurationController,
+ statusBarService,
+ notificationManager,
visibilityProvider,
- interruptionStateProvider, zenModeController, notifUserManager,
- groupManager, entryManager, notifCollection, notifPipeline, sysUiState,
- notifPipelineFlags, dumpManager, sysuiMainExecutor);
+ interruptionStateProvider,
+ zenModeController,
+ notifUserManager,
+ groupManager,
+ entryManager,
+ notifCollection,
+ notifPipeline,
+ sysUiState,
+ notifPipelineFlags,
+ dumpManager,
+ sysuiMainExecutor);
} else {
return null;
}
@@ -166,7 +178,7 @@ public class BubblesManager implements Dumpable {
BubblesManager(Context context,
Bubbles bubbles,
NotificationShadeWindowController notificationShadeWindowController,
- StatusBarStateController statusBarStateController,
+ KeyguardStateController keyguardStateController,
ShadeController shadeController,
ConfigurationController configurationController,
@Nullable IStatusBarService statusBarService,
@@ -210,11 +222,12 @@ public class BubblesManager implements Dumpable {
dumpManager.registerDumpable(TAG, this);
- statusBarStateController.addCallback(new StatusBarStateController.StateListener() {
+ keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@Override
- public void onStateChanged(int newState) {
- boolean isShade = newState == SHADE;
- bubbles.onStatusBarStateChanged(isShade);
+ public void onKeyguardShowingChanged() {
+ boolean isUnlockedShade = !keyguardStateController.isShowing()
+ && !keyguardStateController.isOccluded();
+ bubbles.onStatusBarStateChanged(isUnlockedShade);
}
});
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index c2439df6624a..3e1b4d63f36a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -45,6 +45,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -101,6 +102,8 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
private ClockPlugin mClockPlugin;
@Mock
ColorExtractor.GradientColors mGradientColors;
+ @Mock
+ DumpManager mDumpManager;
@Mock
private NotificationIconContainer mNotificationIcons;
@@ -149,12 +152,12 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
mBroadcastDispatcher,
mBatteryController,
mKeyguardUpdateMonitor,
- mBypassController,
mSmartspaceController,
mKeyguardUnlockAnimationController,
mSecureSettings,
mExecutor,
- mResources
+ mResources,
+ mDumpManager
);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
index 8eb0918beedf..98d57a3c5da8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
@@ -9,8 +9,10 @@ import android.widget.LinearLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertNull
+import junit.framework.Assert.assertTrue
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -25,15 +27,23 @@ class ViewHierarchyAnimatorTest : SysuiTestCase() {
private val TEST_INTERPOLATOR = Interpolators.LINEAR
}
+ private val childParams = LinearLayout.LayoutParams(
+ 0 /* width */,
+ LinearLayout.LayoutParams.MATCH_PARENT
+ )
private lateinit var rootView: LinearLayout
@Before
fun setUp() {
rootView = LinearLayout(mContext)
+ rootView.orientation = LinearLayout.HORIZONTAL
+ rootView.weightSum = 1f
+ childParams.weight = 0.5f
}
@After
fun tearDown() {
+ endAnimation(rootView)
ViewHierarchyAnimator.stopAnimating(rootView)
}
@@ -41,13 +51,45 @@ class ViewHierarchyAnimatorTest : SysuiTestCase() {
fun respectsAnimationParameters() {
rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
- ViewHierarchyAnimator.animate(
+ // animate()
+ var success = ViewHierarchyAnimator.animate(
rootView, interpolator = TEST_INTERPOLATOR, duration = TEST_DURATION
)
rootView.layout(0 /* l */, 0 /* t */, 100 /* r */, 100 /* b */)
+ assertTrue(success)
assertNotNull(rootView.getTag(R.id.tag_animator))
- val animator = rootView.getTag(R.id.tag_animator) as ObjectAnimator
+ var animator = rootView.getTag(R.id.tag_animator) as ObjectAnimator
+ assertEquals(animator.interpolator, TEST_INTERPOLATOR)
+ assertEquals(animator.duration, TEST_DURATION)
+
+ endAnimation(rootView)
+ ViewHierarchyAnimator.stopAnimating(rootView)
+
+ // animateNextUpdate()
+ success = ViewHierarchyAnimator.animateNextUpdate(
+ rootView, interpolator = TEST_INTERPOLATOR, duration = TEST_DURATION
+ )
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ animator = rootView.getTag(R.id.tag_animator) as ObjectAnimator
+ assertEquals(animator.interpolator, TEST_INTERPOLATOR)
+ assertEquals(animator.duration, TEST_DURATION)
+
+ endAnimation(rootView)
+
+ // animateAddition()
+ rootView.layout(0 /* l */, 0 /* t */, 0 /* r */, 0 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView, interpolator = TEST_INTERPOLATOR, duration = TEST_DURATION
+ )
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ animator = rootView.getTag(R.id.tag_animator) as ObjectAnimator
assertEquals(animator.interpolator, TEST_INTERPOLATOR)
assertEquals(animator.duration, TEST_DURATION)
}
@@ -56,10 +98,11 @@ class ViewHierarchyAnimatorTest : SysuiTestCase() {
fun animatesFromStartToEnd() {
rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
- ViewHierarchyAnimator.animate(rootView)
+ val success = ViewHierarchyAnimator.animate(rootView)
// Change all bounds.
rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+ assertTrue(success)
assertNotNull(rootView.getTag(R.id.tag_animator))
// The initial values should be those of the previous layout.
checkBounds(rootView, l = 10, t = 10, r = 50, b = 50)
@@ -73,10 +116,11 @@ class ViewHierarchyAnimatorTest : SysuiTestCase() {
fun animatesSuccessiveLayoutChanges() {
rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
- ViewHierarchyAnimator.animate(rootView)
+ val success = ViewHierarchyAnimator.animate(rootView)
// Change all bounds.
rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+ assertTrue(success)
assertNotNull(rootView.getTag(R.id.tag_animator))
endAnimation(rootView)
assertNull(rootView.getTag(R.id.tag_animator))
@@ -103,10 +147,12 @@ class ViewHierarchyAnimatorTest : SysuiTestCase() {
fun animatesFromPreviousAnimationProgress() {
rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
- ViewHierarchyAnimator.animateNextUpdate(rootView, interpolator = TEST_INTERPOLATOR)
+ val success =
+ ViewHierarchyAnimator.animateNextUpdate(rootView, interpolator = TEST_INTERPOLATOR)
// Change all bounds.
rootView.layout(0 /* l */, 20 /* t */, 70 /* r */, 80 /* b */)
+ assertTrue(success)
assertNotNull(rootView.getTag(R.id.tag_animator))
advanceAnimation(rootView, fraction = 0.5f)
checkBounds(rootView, l = 5, t = 15, r = 60, b = 65)
@@ -124,57 +170,448 @@ class ViewHierarchyAnimatorTest : SysuiTestCase() {
@Test
fun animatesRootAndChildren() {
val firstChild = View(mContext)
+ firstChild.layoutParams = childParams
rootView.addView(firstChild)
val secondChild = View(mContext)
+ secondChild.layoutParams = childParams
rootView.addView(secondChild)
+ rootView.measure(
+ View.MeasureSpec.makeMeasureSpec(150, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
+ )
rootView.layout(0 /* l */, 0 /* t */, 150 /* r */, 100 /* b */)
- firstChild.layout(0 /* l */, 0 /* t */, 100 /* r */, 100 /* b */)
- secondChild.layout(100 /* l */, 0 /* t */, 150 /* r */, 100 /* b */)
- ViewHierarchyAnimator.animate(rootView)
+ val success = ViewHierarchyAnimator.animate(rootView)
// Change all bounds.
+ rootView.measure(
+ View.MeasureSpec.makeMeasureSpec(190, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
+ )
rootView.layout(10 /* l */, 20 /* t */, 200 /* r */, 120 /* b */)
- firstChild.layout(10 /* l */, 20 /* t */, 150 /* r */, 120 /* b */)
- secondChild.layout(150 /* l */, 20 /* t */, 200 /* r */, 120 /* b */)
+ assertTrue(success)
assertNotNull(rootView.getTag(R.id.tag_animator))
+ assertNotNull(firstChild.getTag(R.id.tag_animator))
+ assertNotNull(secondChild.getTag(R.id.tag_animator))
// The initial values should be those of the previous layout.
checkBounds(rootView, l = 0, t = 0, r = 150, b = 100)
- checkBounds(firstChild, l = 0, t = 0, r = 100, b = 100)
- checkBounds(secondChild, l = 100, t = 0, r = 150, b = 100)
+ checkBounds(firstChild, l = 0, t = 0, r = 75, b = 100)
+ checkBounds(secondChild, l = 75, t = 0, r = 150, b = 100)
endAnimation(rootView)
assertNull(rootView.getTag(R.id.tag_animator))
+ assertNull(firstChild.getTag(R.id.tag_animator))
+ assertNull(secondChild.getTag(R.id.tag_animator))
// The end values should be those of the latest layout.
checkBounds(rootView, l = 10, t = 20, r = 200, b = 120)
- checkBounds(firstChild, l = 10, t = 20, r = 150, b = 120)
- checkBounds(secondChild, l = 150, t = 20, r = 200, b = 120)
+ checkBounds(firstChild, l = 0, t = 0, r = 95, b = 100)
+ checkBounds(secondChild, l = 95, t = 0, r = 190, b = 100)
+ }
+
+ @Test
+ fun animatesAppearingViewsFromStartToEnd() {
+ // Starting GONE.
+ rootView.visibility = View.GONE
+ rootView.layout(0 /* l */, 50 /* t */, 50 /* r */, 100 /* b */)
+ var success = ViewHierarchyAnimator.animateAddition(rootView)
+ rootView.visibility = View.VISIBLE
+ rootView.layout(0 /* l */, 100 /* t */, 100 /* r */, 200 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 50, t = 150, r = 50, b = 150)
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 100, r = 100, b = 200)
+
+ // Starting INVISIBLE.
+ rootView.visibility = View.INVISIBLE
+ rootView.layout(0 /* l */, 50 /* t */, 50 /* r */, 100 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(rootView)
+ rootView.visibility = View.VISIBLE
+ rootView.layout(0 /* l */, 100 /* t */, 100 /* r */, 200 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 50, t = 150, r = 50, b = 150)
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 100, r = 100, b = 200)
+
+ // Starting with nothing.
+ rootView.layout(0 /* l */, 0 /* t */, 0 /* r */, 0 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(rootView)
+ rootView.layout(0 /* l */, 20 /* t */, 50 /* r */, 80 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 25, t = 50, r = 25, b = 50)
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 20, r = 50, b = 80)
+
+ // Starting with 0 width.
+ rootView.layout(0 /* l */, 50 /* t */, 0 /* r */, 100 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(rootView)
+ rootView.layout(0 /* l */, 50 /* t */, 50 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 25, t = 75, r = 25, b = 75)
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 50, r = 50, b = 100)
+
+ // Starting with 0 height.
+ rootView.layout(0 /* l */, 50 /* t */, 50 /* r */, 50 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(rootView)
+ rootView.layout(0 /* l */, 50 /* t */, 50 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 25, t = 75, r = 25, b = 75)
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 50, r = 50, b = 100)
+ }
+
+ @Test
+ fun animatesAppearingViewsRespectingOrigin() {
+ // CENTER.
+ rootView.layout(0 /* l */, 0 /* t */, 0 /* r */, 0 /* b */)
+ var success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.CENTER
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 75, t = 75, r = 75, b = 75)
+ endAnimation(rootView)
+
+ // LEFT.
+ rootView.layout(0 /* l */, 0 /* t */, 0 /* r */, 0 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.LEFT
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 50, t = 50, r = 50, b = 100)
+ endAnimation(rootView)
+
+ // TOP_LEFT.
+ rootView.layout(0 /* l */, 0 /* t */, 0 /* r */, 0 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.TOP_LEFT
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 50, t = 50, r = 50, b = 50)
+ endAnimation(rootView)
+
+ // TOP.
+ rootView.layout(150 /* l */, 0 /* t */, 150 /* r */, 0 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.TOP
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 50, t = 50, r = 100, b = 50)
+ endAnimation(rootView)
+
+ // TOP_RIGHT.
+ rootView.layout(150 /* l */, 0 /* t */, 150 /* r */, 0 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.TOP_RIGHT
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 100, t = 50, r = 100, b = 50)
+ endAnimation(rootView)
+
+ // RIGHT.
+ rootView.layout(150 /* l */, 150 /* t */, 150 /* r */, 150 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.RIGHT
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 100, t = 50, r = 100, b = 100)
+ endAnimation(rootView)
+
+ // BOTTOM_RIGHT.
+ rootView.layout(150 /* l */, 150 /* t */, 150 /* r */, 150 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.BOTTOM_RIGHT
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 100, t = 100, r = 100, b = 100)
+ endAnimation(rootView)
+
+ // BOTTOM.
+ rootView.layout(0 /* l */, 150 /* t */, 0 /* r */, 150 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.BOTTOM
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 50, t = 100, r = 100, b = 100)
+ endAnimation(rootView)
+
+ // BOTTOM_LEFT.
+ rootView.layout(0 /* l */, 150 /* t */, 0 /* r */, 150 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.BOTTOM_LEFT
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 50, t = 100, r = 50, b = 100)
+ endAnimation(rootView)
+ }
+
+ @Test
+ fun animatesAppearingViewsRespectingMargins() {
+ // CENTER.
+ rootView.layout(0 /* l */, 0 /* t */, 0 /* r */, 0 /* b */)
+ var success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.CENTER,
+ includeMargins = true
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 75, t = 75, r = 75, b = 75)
+ endAnimation(rootView)
+
+ // LEFT.
+ rootView.layout(0 /* l */, 0 /* t */, 0 /* r */, 0 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView, origin = ViewHierarchyAnimator.Hotspot.LEFT,
+ includeMargins = true
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 50, r = 0, b = 100)
+ endAnimation(rootView)
+
+ // TOP_LEFT.
+ rootView.layout(0 /* l */, 0 /* t */, 0 /* r */, 0 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.TOP_LEFT,
+ includeMargins = true
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 0, r = 0, b = 0)
+ endAnimation(rootView)
+
+ // TOP.
+ rootView.layout(150 /* l */, 0 /* t */, 150 /* r */, 0 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView, origin = ViewHierarchyAnimator.Hotspot.TOP,
+ includeMargins = true
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 50, t = 0, r = 100, b = 0)
+ endAnimation(rootView)
+
+ // TOP_RIGHT.
+ rootView.layout(150 /* l */, 0 /* t */, 150 /* r */, 0 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.TOP_RIGHT,
+ includeMargins = true
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 150, t = 0, r = 150, b = 0)
+ endAnimation(rootView)
+
+ // RIGHT.
+ rootView.layout(150 /* l */, 150 /* t */, 150 /* r */, 150 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.RIGHT,
+ includeMargins = true
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 150, t = 50, r = 150, b = 100)
+ endAnimation(rootView)
+
+ // BOTTOM_RIGHT.
+ rootView.layout(150 /* l */, 150 /* t */, 150 /* r */, 150 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.BOTTOM_RIGHT,
+ includeMargins = true
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 150, t = 150, r = 150, b = 150)
+ endAnimation(rootView)
+
+ // BOTTOM.
+ rootView.layout(0 /* l */, 150 /* t */, 0 /* r */, 150 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.BOTTOM,
+ includeMargins = true
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 50, t = 150, r = 100, b = 150)
+ endAnimation(rootView)
+
+ // BOTTOM_LEFT.
+ rootView.layout(0 /* l */, 150 /* t */, 0 /* r */, 150 /* b */)
+ success = ViewHierarchyAnimator.animateAddition(
+ rootView,
+ origin = ViewHierarchyAnimator.Hotspot.BOTTOM_LEFT,
+ includeMargins = true
+ )
+ rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */)
+
+ assertTrue(success)
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 150, r = 0, b = 150)
+ endAnimation(rootView)
}
@Test
fun doesNotAnimateInvisibleViews() {
rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
- ViewHierarchyAnimator.animate(rootView)
- // GONE.
+ // GONE
rootView.visibility = View.GONE
+ var success = ViewHierarchyAnimator.animate(rootView)
rootView.layout(0 /* l */, 15 /* t */, 55 /* r */, 80 /* b */)
+ assertFalse(success)
assertNull(rootView.getTag(R.id.tag_animator))
checkBounds(rootView, l = 0, t = 15, r = 55, b = 80)
// INVISIBLE.
rootView.visibility = View.INVISIBLE
- rootView.layout(0 /* l */, 20 /* t */, 0 /* r */, 20 /* b */)
+ success = ViewHierarchyAnimator.animate(rootView)
+ rootView.layout(0 /* l */, 20 /* t */, 10 /* r */, 50 /* b */)
+
+ assertFalse(success)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 20, r = 10, b = 50)
+ }
+
+ @Test
+ fun doesNotAnimateAppearingViews() {
+ // Starting with nothing.
+ rootView.layout(0 /* l */, 0 /* t */, 0 /* r */, 0 /* b */)
+ var success = ViewHierarchyAnimator.animate(rootView)
+ rootView.layout(0 /* l */, 15 /* t */, 55 /* r */, 80 /* b */)
+
+ assertFalse(success)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 15, r = 55, b = 80)
+
+ // Starting with 0 width.
+ rootView.layout(0 /* l */, 50 /* t */, 0 /* r */, 100 /* b */)
+ success = ViewHierarchyAnimator.animate(rootView)
+ rootView.layout(0 /* l */, 15 /* t */, 55 /* r */, 80 /* b */)
+
+ assertFalse(success)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 15, r = 55, b = 80)
+
+ // Starting with 0 height.
+ rootView.layout(0 /* l */, 50 /* t */, 50 /* r */, 50 /* b */)
+ success = ViewHierarchyAnimator.animate(rootView)
+ rootView.layout(0 /* l */, 15 /* t */, 55 /* r */, 80 /* b */)
+
+ assertFalse(success)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 15, r = 55, b = 80)
+ }
+
+ @Test
+ fun doesNotAnimateDisappearingViews() {
+ rootView.layout(0 /* l */, 0 /* t */, 100 /* r */, 100 /* b */)
+
+ val success = ViewHierarchyAnimator.animate(rootView)
+ // Ending with nothing.
+ rootView.layout(0 /* l */, 0 /* t */, 0 /* r */, 0 /* b */)
+
+ assertTrue(success)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 0, r = 0, b = 0)
+
+ // Ending with 0 width.
+ rootView.layout(0 /* l */, 50 /* t */, 50 /* r */, 100 /* b */)
+ endAnimation(rootView)
+ rootView.layout(0 /* l */, 15 /* t */, 0 /* r */, 80 /* b */)
+
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 15, r = 0, b = 80)
+
+ // Ending with 0 height.
+ rootView.layout(0 /* l */, 50 /* t */, 50 /* r */, 100 /* b */)
+ endAnimation(rootView)
+ rootView.layout(0 /* l */, 50 /* t */, 55 /* r */, 50 /* b */)
+
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 50, r = 55, b = 50)
}
@Test
fun doesNotAnimateUnchangingBounds() {
rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
- ViewHierarchyAnimator.animate(rootView)
+ val success = ViewHierarchyAnimator.animate(rootView)
// No bounds are changed.
rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+ assertTrue(success)
assertNull(rootView.getTag(R.id.tag_animator))
checkBounds(rootView, l = 10, t = 10, r = 50, b = 50)
@@ -191,7 +628,7 @@ class ViewHierarchyAnimatorTest : SysuiTestCase() {
fun doesNotAnimateExcludedBounds() {
rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
- ViewHierarchyAnimator.animate(
+ val success = ViewHierarchyAnimator.animate(
rootView,
bounds = setOf(ViewHierarchyAnimator.Bound.LEFT, ViewHierarchyAnimator.Bound.TOP),
interpolator = TEST_INTERPOLATOR
@@ -199,6 +636,7 @@ class ViewHierarchyAnimatorTest : SysuiTestCase() {
// Change all bounds.
rootView.layout(0 /* l */, 20 /* t */, 70 /* r */, 80 /* b */)
+ assertTrue(success)
assertNotNull(rootView.getTag(R.id.tag_animator))
advanceAnimation(rootView, 0.5f)
checkBounds(rootView, l = 5, t = 15, r = 70, b = 80)
@@ -211,10 +649,11 @@ class ViewHierarchyAnimatorTest : SysuiTestCase() {
fun stopsAnimatingAfterSingleLayout() {
rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
- ViewHierarchyAnimator.animateNextUpdate(rootView)
+ val success = ViewHierarchyAnimator.animateNextUpdate(rootView)
// Change all bounds.
rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+ assertTrue(success)
assertNotNull(rootView.getTag(R.id.tag_animator))
endAnimation(rootView)
assertNull(rootView.getTag(R.id.tag_animator))
@@ -231,10 +670,11 @@ class ViewHierarchyAnimatorTest : SysuiTestCase() {
fun stopsAnimatingWhenInstructed() {
rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
- ViewHierarchyAnimator.animate(rootView)
+ val success = ViewHierarchyAnimator.animate(rootView)
// Change all bounds.
rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+ assertTrue(success)
assertNotNull(rootView.getTag(R.id.tag_animator))
endAnimation(rootView)
assertNull(rootView.getTag(R.id.tag_animator))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index a95da6295350..5440b45a778f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -299,7 +299,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
`when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
`when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
- controller.showRipple(BiometricSourceType.FINGERPRINT)
+ controller.showUnlockRipple(BiometricSourceType.FINGERPRINT)
assertTrue("reveal didn't start on keyguardFadingAway",
controller.startLightRevealScrimOnKeyguardFadingAway)
`when`(keyguardStateController.isKeyguardFadingAway).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
index e15b6cc62644..de04d3e9d059 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
@@ -32,6 +32,7 @@ import android.provider.DeviceConfig;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.DeviceConfigProxyFake;
@@ -53,6 +54,8 @@ public class ClipboardListenerTest extends SysuiTestCase {
private ClipboardOverlayControllerFactory mClipboardOverlayControllerFactory;
@Mock
private ClipboardOverlayController mOverlayController;
+ @Mock
+ private UiEventLogger mUiEventLogger;
private DeviceConfigProxyFake mDeviceConfigProxy;
private ClipData mSampleClipData;
@@ -87,9 +90,10 @@ public class ClipboardListenerTest extends SysuiTestCase {
mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
"false", false);
ClipboardListener listener = new ClipboardListener(getContext(), mDeviceConfigProxy,
- mClipboardOverlayControllerFactory, mClipboardManager);
+ mClipboardOverlayControllerFactory, mClipboardManager, mUiEventLogger);
listener.start();
verifyZeroInteractions(mClipboardManager);
+ verifyZeroInteractions(mUiEventLogger);
}
@Test
@@ -97,9 +101,10 @@ public class ClipboardListenerTest extends SysuiTestCase {
mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
"true", false);
ClipboardListener listener = new ClipboardListener(getContext(), mDeviceConfigProxy,
- mClipboardOverlayControllerFactory, mClipboardManager);
+ mClipboardOverlayControllerFactory, mClipboardManager, mUiEventLogger);
listener.start();
verify(mClipboardManager).addPrimaryClipChangedListener(any());
+ verifyZeroInteractions(mUiEventLogger);
}
@Test
@@ -107,7 +112,7 @@ public class ClipboardListenerTest extends SysuiTestCase {
mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
"true", false);
ClipboardListener listener = new ClipboardListener(getContext(), mDeviceConfigProxy,
- mClipboardOverlayControllerFactory, mClipboardManager);
+ mClipboardOverlayControllerFactory, mClipboardManager, mUiEventLogger);
listener.start();
listener.onPrimaryClipChanged();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayEventTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayEventTest.java
new file mode 100644
index 000000000000..c7c2cd8d7b4b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayEventTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2022 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.clipboardoverlay;
+
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_ENABLED;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.provider.DeviceConfig;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.DeviceConfigProxyFake;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ClipboardOverlayEventTest extends SysuiTestCase {
+
+ @Mock
+ private ClipboardManager mClipboardManager;
+ @Mock
+ private ClipboardOverlayControllerFactory mClipboardOverlayControllerFactory;
+ @Mock
+ private ClipboardOverlayController mOverlayController;
+ @Mock
+ private UiEventLogger mUiEventLogger;
+
+ private final String mSampleSource = "Example source";
+
+ private ClipboardListener mClipboardListener;
+
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ when(mClipboardOverlayControllerFactory.create(any())).thenReturn(
+ mOverlayController);
+ when(mClipboardManager.hasPrimaryClip()).thenReturn(true);
+
+ ClipData sampleClipData = new ClipData("Test", new String[]{"text/plain"},
+ new ClipData.Item("Test Item"));
+ when(mClipboardManager.getPrimaryClip()).thenReturn(sampleClipData);
+ when(mClipboardManager.getPrimaryClipSource()).thenReturn(mSampleSource);
+
+ DeviceConfigProxyFake deviceConfigProxy = new DeviceConfigProxyFake();
+ deviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
+ "true", false);
+
+ mClipboardListener = new ClipboardListener(getContext(), deviceConfigProxy,
+ mClipboardOverlayControllerFactory, mClipboardManager, mUiEventLogger);
+ }
+
+ @Test
+ public void test_enterAndReenter() {
+ mClipboardListener.start();
+
+ mClipboardListener.onPrimaryClipChanged();
+ mClipboardListener.onPrimaryClipChanged();
+
+ verify(mUiEventLogger, times(1)).log(
+ ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED, 0, mSampleSource);
+ verify(mUiEventLogger, times(1)).log(
+ ClipboardOverlayEvent.CLIPBOARD_OVERLAY_UPDATED, 0, mSampleSource);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
index b536bfdb944e..2effaec58a86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
@@ -75,7 +75,7 @@ class RoundedCornerResDelegateTest : SysuiTestCase() {
fun testUpdateTuningSizeFactor() {
mContext.orCreateTestableResources.addOverrides(
mockTypeArray = mockTypedArray,
- radiusTop = 0,
+ radiusTop = 2,
radiusBottom = 0,
multipleRadius = false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
index c86122141c8f..b7de6c15459c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
@@ -61,7 +61,8 @@ public class DreamOverlayNotificationCountProviderTest extends SysuiTestCase {
final StatusBarNotification[] notifications = {mNotification1};
when(mNotificationListener.getActiveNotifications()).thenReturn(notifications);
- mProvider = new DreamOverlayNotificationCountProvider(mNotificationListener);
+ mProvider = new DreamOverlayNotificationCountProvider(
+ mNotificationListener, Runnable::run);
mProvider.addCallback(mCallback);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index 629c531f0a56..74cf49758ac6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -166,6 +166,76 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
}
/**
+ * Makes sure swiping up when bouncer initially showing doesn't change the expansion amount.
+ */
+ @Test
+ public void testSwipeUp_whenBouncerInitiallyShowing_keepsExpansionAtZero() {
+ when(mCentralSurfaces.isBouncerShowing()).thenReturn(true);
+
+ mTouchHandler.onSessionStart(mTouchSession);
+ ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
+ ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class);
+ verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture());
+
+ final OnGestureListener gestureListener = gestureListenerCaptor.getValue();
+
+ final float percent = .3f;
+ final float distanceY = SCREEN_HEIGHT_PX * percent;
+
+ // Swiping up near the top of the screen where the touch initiation region is.
+ final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
+ 0, distanceY, 0);
+ final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
+ 0, 0, 0);
+
+ assertThat(gestureListener.onScroll(event1, event2, 0, distanceY))
+ .isTrue();
+
+ // Ensure only called once
+ verify(mStatusBarKeyguardViewManager)
+ .onPanelExpansionChanged(anyFloat(), anyBoolean(), anyBoolean());
+
+ // TODO(b/227348372): update the logic and also this test.
+ // Ensure the expansion is kept at 0.
+ verify(mStatusBarKeyguardViewManager).onPanelExpansionChanged(eq(0f), eq(false),
+ eq(true));
+ }
+
+ /**
+ * Makes sure swiping down when bouncer initially hidden doesn't change the expansion amount.
+ */
+ @Test
+ public void testSwipeDown_whenBouncerInitiallyHidden_keepsExpansionAtOne() {
+ mTouchHandler.onSessionStart(mTouchSession);
+ ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
+ ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class);
+ verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture());
+
+ final OnGestureListener gestureListener = gestureListenerCaptor.getValue();
+
+ final float percent = .15f;
+ final float distanceY = SCREEN_HEIGHT_PX * percent;
+
+ // Swiping down near the bottom of the screen where the touch initiation region is.
+ final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
+ 0, SCREEN_HEIGHT_PX - distanceY, 0);
+ final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
+ 0, SCREEN_HEIGHT_PX, 0);
+
+ assertThat(gestureListener.onScroll(event1, event2, 0, distanceY))
+ .isTrue();
+
+ // Ensure only called once
+ verify(mStatusBarKeyguardViewManager)
+ .onPanelExpansionChanged(anyFloat(), anyBoolean(), anyBoolean());
+
+ // TODO(b/227348372): update the logic and also this test.
+ // Ensure the expansion is kept at 1.
+ verify(mStatusBarKeyguardViewManager).onPanelExpansionChanged(eq(1f), eq(false),
+ eq(true));
+ }
+
+ /**
* Makes sure the expansion amount is proportional to (1 - scroll).
*/
@Test
@@ -176,12 +246,13 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture());
final OnGestureListener gestureListener = gestureListenerCaptor.getValue();
- verifyScroll(.3f, Direction.UP, true, gestureListener);
+
+ verifyScroll(.3f, Direction.UP, false, gestureListener);
// Ensure that subsequent gestures are treated as expanding even if the bouncer state
// changes.
when(mCentralSurfaces.isBouncerShowing()).thenReturn(true);
- verifyScroll(.7f, Direction.UP, true, gestureListener);
+ verifyScroll(.7f, Direction.UP, false, gestureListener);
}
/**
@@ -197,17 +268,17 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture());
final OnGestureListener gestureListener = gestureListenerCaptor.getValue();
- verifyScroll(.3f, Direction.DOWN, false, gestureListener);
+
+ verifyScroll(.3f, Direction.DOWN, true, gestureListener);
// Ensure that subsequent gestures are treated as collapsing even if the bouncer state
// changes.
when(mCentralSurfaces.isBouncerShowing()).thenReturn(false);
- verifyScroll(.7f, Direction.DOWN, false, gestureListener);
+ verifyScroll(.7f, Direction.DOWN, true, gestureListener);
}
- private void verifyScroll(float percent, Direction direction, boolean expanding,
- android.view.GestureDetector.OnGestureListener gestureListener) {
-
+ private void verifyScroll(float percent, Direction direction,
+ boolean isBouncerInitiallyShowing, GestureDetector.OnGestureListener gestureListener) {
final float distanceY = SCREEN_HEIGHT_PX * percent;
final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
@@ -223,10 +294,11 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
verify(mStatusBarKeyguardViewManager)
.onPanelExpansionChanged(anyFloat(), anyBoolean(), anyBoolean());
+ final float expansion = isBouncerInitiallyShowing ? percent : 1 - percent;
+
// Ensure correct expansion passed in.
- verify(mStatusBarKeyguardViewManager)
- .onPanelExpansionChanged(
- eq(expanding ? 1 - percent : percent), eq(false), eq(true));
+ verify(mStatusBarKeyguardViewManager).onPanelExpansionChanged(eq(expansion), eq(false),
+ eq(true));
}
/**
@@ -340,9 +412,9 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
mTouchHandler.onSessionStart(mTouchSession);
ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class);
+ verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture());
ArgumentCaptor<InputChannelCompat.InputEventListener> inputEventListenerCaptor =
ArgumentCaptor.forClass(InputChannelCompat.InputEventListener.class);
- verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture());
verify(mTouchSession).registerInputListener(inputEventListenerCaptor.capture());
when(mVelocityTracker.getYVelocity()).thenReturn(velocityY);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
index daf81bdc6e82..46e675684782 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -35,26 +35,11 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import javax.inject.Provider
-private val DATA = MediaData(
- userId = -1,
- initialized = false,
- backgroundColor = 0,
- app = null,
- appIcon = null,
- artist = null,
- song = null,
- artwork = null,
- actions = emptyList(),
- actionsToShowInCompact = emptyList(),
- packageName = "INVALID",
- token = null,
- clickIntent = null,
- device = null,
- active = true,
- resumeAction = null)
+private val DATA = MediaTestUtils.emptyMediaData
private val SMARTSPACE_KEY = "smartspace"
@@ -74,7 +59,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
@Mock lateinit var falsingCollector: FalsingCollector
@Mock lateinit var falsingManager: FalsingManager
@Mock lateinit var dumpManager: DumpManager
- @Mock lateinit var mediaFlags: MediaFlags
+ @Mock lateinit var logger: MediaUiEventLogger
private val clock = FakeSystemClock()
private lateinit var mediaCarouselController: MediaCarouselController
@@ -95,7 +80,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
falsingCollector,
falsingManager,
dumpManager,
- mediaFlags
+ logger
)
MediaPlayerData.clear()
@@ -189,4 +174,18 @@ class MediaCarouselControllerTest : SysuiTestCase() {
val size = MediaPlayerData.playerKeys().size
assertTrue(MediaPlayerData.playerKeys().elementAt(size - 1).isSsMediaRec)
}
+
+ @Test
+ fun testSwipeDismiss_logged() {
+ mediaCarouselController.mediaCarouselScrollHandler.dismissCallback.invoke()
+
+ verify(logger).logSwipeDismiss()
+ }
+
+ @Test
+ fun testSettingsButton_logged() {
+ mediaCarouselController.settingsButton.callOnClick()
+
+ verify(logger).logCarouselSettings()
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 63b3a7db40d3..f2e3edbc0761 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -41,6 +41,7 @@ import androidx.constraintlayout.widget.Barrier
import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.LiveData
import androidx.test.filters.SmallTest
+import com.android.internal.logging.InstanceId
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastSender
@@ -49,6 +50,7 @@ import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.util.animation.TransitionLayout
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.KotlinArgumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -59,6 +61,7 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Mock
import org.mockito.Mockito.any
@@ -69,7 +72,6 @@ import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
private const val KEY = "TEST_KEY"
-private const val APP = "APP"
private const val BG_COLOR = Color.RED
private const val PACKAGE = "PKG"
private const val ARTIST = "ARTIST"
@@ -78,7 +80,6 @@ private const val DEVICE_NAME = "DEVICE_NAME"
private const val SESSION_KEY = "SESSION_KEY"
private const val SESSION_ARTIST = "SESSION_ARTIST"
private const val SESSION_TITLE = "SESSION_TITLE"
-private const val USER_ID = 0
private const val DISABLED_DEVICE_NAME = "DISABLED_DEVICE_NAME"
@SmallTest
@@ -137,6 +138,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
private val disabledDevice = MediaDeviceData(false, null, DISABLED_DEVICE_NAME)
private lateinit var mediaData: MediaData
private val clock = FakeSystemClock()
+ @Mock private lateinit var logger: MediaUiEventLogger
+ @Mock private lateinit var instanceId: InstanceId
@JvmField @Rule val mockito = MockitoJUnit.rule()
@@ -148,7 +151,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
player = MediaControlPanel(context, bgExecutor, activityStarter, broadcastSender,
mediaViewController, seekBarViewModel, Lazy { mediaDataManager },
- mediaOutputDialogFactory, mediaCarouselController, falsingManager, clock)
+ mediaOutputDialogFactory, mediaCarouselController, falsingManager, clock, logger)
whenever(seekBarViewModel.progress).thenReturn(seekBarData)
// Set up mock views for the players
@@ -212,23 +215,14 @@ public class MediaControlPanelTest : SysuiTestCase() {
}
session.setActive(true)
- mediaData = MediaData(
- userId = USER_ID,
- initialized = true,
+ mediaData = MediaTestUtils.emptyMediaData.copy(
backgroundColor = BG_COLOR,
- app = APP,
- appIcon = null,
artist = ARTIST,
song = TITLE,
- artwork = null,
- actions = emptyList(),
- actionsToShowInCompact = emptyList(),
packageName = PACKAGE,
token = session.sessionToken,
- clickIntent = null,
device = device,
- active = true,
- resumeAction = null)
+ instanceId = instanceId)
}
/**
@@ -534,6 +528,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun longClick_gutsClosed() {
player.attachPlayer(viewHolder)
+ player.bindPlayer(mediaData, KEY)
whenever(mediaViewController.isGutsVisible).thenReturn(false)
val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
@@ -541,6 +536,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
captor.value.onLongClick(viewHolder.player)
verify(mediaViewController).openGuts()
+ verify(logger).logLongPressOpen(anyInt(), eq(PACKAGE), eq(instanceId))
}
@Test
@@ -568,8 +564,10 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun settingsButtonClick() {
player.attachPlayer(viewHolder)
+ player.bindPlayer(mediaData, KEY)
settings.callOnClick()
+ verify(logger).logLongPressSettings(anyInt(), eq(PACKAGE), eq(instanceId))
val captor = ArgumentCaptor.forClass(Intent::class.java)
verify(activityStarter).startActivity(captor.capture(), eq(true))
@@ -586,6 +584,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
assertThat(dismiss.isEnabled).isEqualTo(true)
dismiss.callOnClick()
+ verify(logger).logLongPressDismiss(anyInt(), eq(PACKAGE), eq(instanceId))
verify(mediaDataManager).dismissMediaData(eq(mediaKey), anyLong())
}
@@ -614,4 +613,151 @@ public class MediaControlPanelTest : SysuiTestCase() {
verify(mediaDataManager).dismissMediaData(eq(mediaKey), anyLong())
verify(mediaCarouselController).removePlayer(eq(mediaKey), eq(false), eq(false))
}
+
+ @Test
+ fun actionPlayPauseClick_isLogged() {
+ val semanticActions = MediaButton(
+ playOrPause = MediaAction(null, Runnable {}, "play", null)
+ )
+ val data = mediaData.copy(semanticActions = semanticActions)
+
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(data, KEY)
+
+ viewHolder.actionPlayPause.callOnClick()
+ verify(logger).logTapAction(eq(R.id.actionPlayPause), anyInt(), eq(PACKAGE), eq(instanceId))
+ }
+
+ @Test
+ fun actionPrevClick_isLogged() {
+ val semanticActions = MediaButton(
+ prevOrCustom = MediaAction(null, Runnable {}, "previous", null)
+ )
+ val data = mediaData.copy(semanticActions = semanticActions)
+
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(data, KEY)
+
+ viewHolder.actionPrev.callOnClick()
+ verify(logger).logTapAction(eq(R.id.actionPrev), anyInt(), eq(PACKAGE), eq(instanceId))
+ }
+
+ @Test
+ fun actionNextClick_isLogged() {
+ val semanticActions = MediaButton(
+ nextOrCustom = MediaAction(null, Runnable {}, "next", null)
+ )
+ val data = mediaData.copy(semanticActions = semanticActions)
+
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(data, KEY)
+
+ viewHolder.actionNext.callOnClick()
+ verify(logger).logTapAction(eq(R.id.actionNext), anyInt(), eq(PACKAGE), eq(instanceId))
+ }
+
+ @Test
+ fun actionCustom0Click_isLogged() {
+ val semanticActions = MediaButton(
+ custom0 = MediaAction(null, Runnable {}, "custom 0", null)
+ )
+ val data = mediaData.copy(semanticActions = semanticActions)
+
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(data, KEY)
+
+ viewHolder.action0.callOnClick()
+ verify(logger).logTapAction(eq(R.id.action0), anyInt(), eq(PACKAGE), eq(instanceId))
+ }
+
+ @Test
+ fun actionCustom1Click_isLogged() {
+ val semanticActions = MediaButton(
+ custom1 = MediaAction(null, Runnable {}, "custom 1", null)
+ )
+ val data = mediaData.copy(semanticActions = semanticActions)
+
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(data, KEY)
+
+ viewHolder.action1.callOnClick()
+ verify(logger).logTapAction(eq(R.id.action1), anyInt(), eq(PACKAGE), eq(instanceId))
+ }
+
+ @Test
+ fun actionCustom2Click_isLogged() {
+ val actions = listOf(
+ MediaAction(null, Runnable {}, "action 0", null),
+ MediaAction(null, Runnable {}, "action 1", null),
+ MediaAction(null, Runnable {}, "action 2", null),
+ MediaAction(null, Runnable {}, "action 3", null),
+ MediaAction(null, Runnable {}, "action 4", null)
+ )
+ val data = mediaData.copy(actions = actions)
+
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(data, KEY)
+
+ viewHolder.action2.callOnClick()
+ verify(logger).logTapAction(eq(R.id.action2), anyInt(), eq(PACKAGE), eq(instanceId))
+ }
+
+ @Test
+ fun actionCustom3Click_isLogged() {
+ val actions = listOf(
+ MediaAction(null, Runnable {}, "action 0", null),
+ MediaAction(null, Runnable {}, "action 1", null),
+ MediaAction(null, Runnable {}, "action 2", null),
+ MediaAction(null, Runnable {}, "action 3", null),
+ MediaAction(null, Runnable {}, "action 4", null)
+ )
+ val data = mediaData.copy(actions = actions)
+
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(data, KEY)
+
+ viewHolder.action1.callOnClick()
+ verify(logger).logTapAction(eq(R.id.action1), anyInt(), eq(PACKAGE), eq(instanceId))
+ }
+
+ @Test
+ fun actionCustom4Click_isLogged() {
+ val actions = listOf(
+ MediaAction(null, Runnable {}, "action 0", null),
+ MediaAction(null, Runnable {}, "action 1", null),
+ MediaAction(null, Runnable {}, "action 2", null),
+ MediaAction(null, Runnable {}, "action 3", null),
+ MediaAction(null, Runnable {}, "action 4", null)
+ )
+ val data = mediaData.copy(actions = actions)
+
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(data, KEY)
+
+ viewHolder.action1.callOnClick()
+ verify(logger).logTapAction(eq(R.id.action1), anyInt(), eq(PACKAGE), eq(instanceId))
+ }
+
+ @Test
+ fun openOutputSwitcher_isLogged() {
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(mediaData, KEY)
+
+ seamless.callOnClick()
+
+ verify(logger).logOpenOutputSwitcher(anyInt(), eq(PACKAGE), eq(instanceId))
+ }
+
+ @Test
+ fun logSeek() {
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(mediaData, KEY)
+
+ val callback: () -> Unit = {}
+ val captor = KotlinArgumentCaptor(callback::class.java)
+ verify(seekBarViewModel).logSeek = captor.capture()
+ captor.value.invoke()
+
+ verify(logger).logSeek(anyInt(), eq(PACKAGE), eq(instanceId))
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
index 7a487b871d9d..b0f6a80bc8a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
@@ -32,6 +32,7 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.InstanceId;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
@@ -77,7 +78,8 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
mMediaData = new MediaData(
USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null,
new ArrayList<>(), new ArrayList<>(), null, PACKAGE, null, null, null, true, null,
- MediaData.PLAYBACK_LOCAL, false, KEY, false, false, false, 0L);
+ MediaData.PLAYBACK_LOCAL, false, KEY, false, false, false, 0L,
+ InstanceId.fakeInstanceId(-1), -1);
mDeviceData = new MediaDeviceData(true, null, DEVICE_NAME);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
index 82a48efafa3a..b8e249fcfeb1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
@@ -17,7 +17,6 @@
package com.android.systemui.media
import android.app.smartspace.SmartspaceAction
-import android.graphics.Color
import androidx.test.filters.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -25,6 +24,8 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -33,7 +34,6 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
-import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
@@ -45,17 +45,9 @@ private const val KEY = "TEST_KEY"
private const val KEY_ALT = "TEST_KEY_2"
private const val USER_MAIN = 0
private const val USER_GUEST = 10
-private const val APP = "APP"
-private const val BG_COLOR = Color.RED
private const val PACKAGE = "PKG"
-private const val ARTIST = "ARTIST"
-private const val TITLE = "TITLE"
-private const val DEVICE_NAME = "DEVICE_NAME"
private const val SMARTSPACE_KEY = "SMARTSPACE_KEY"
-private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
-private fun <T> any(): T = Mockito.any()
-
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
@@ -68,8 +60,6 @@ class MediaDataFilterTest : SysuiTestCase() {
@Mock
private lateinit var broadcastSender: BroadcastSender
@Mock
- private lateinit var mediaResumeListener: MediaResumeListener
- @Mock
private lateinit var mediaDataManager: MediaDataManager
@Mock
private lateinit var lockscreenUserManager: NotificationLockscreenUserManager
@@ -83,7 +73,6 @@ class MediaDataFilterTest : SysuiTestCase() {
private lateinit var mediaDataFilter: MediaDataFilter
private lateinit var dataMain: MediaData
private lateinit var dataGuest: MediaData
- private val device = MediaDeviceData(true, null, DEVICE_NAME)
private val clock = FakeSystemClock()
@Before
@@ -99,23 +88,9 @@ class MediaDataFilterTest : SysuiTestCase() {
setUser(USER_MAIN)
// Set up test media data
- dataMain = MediaData(
+ dataMain = MediaTestUtils.emptyMediaData.copy(
userId = USER_MAIN,
- initialized = true,
- backgroundColor = BG_COLOR,
- app = APP,
- appIcon = null,
- artist = ARTIST,
- song = TITLE,
- artwork = null,
- actions = emptyList(),
- actionsToShowInCompact = emptyList(),
- packageName = PACKAGE,
- token = null,
- clickIntent = null,
- device = device,
- active = true,
- resumeAction = null)
+ packageName = PACKAGE)
dataGuest = dataMain.copy(userId = USER_GUEST)
`when`(smartspaceData.targetId).thenReturn(SMARTSPACE_KEY)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 066f49a16f19..ccd8ef1b7c6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -18,6 +18,7 @@ import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.media.utils.MediaConstants
import androidx.test.filters.SmallTest
+import com.android.systemui.InstanceIdSequenceFake
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -38,10 +39,10 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
-import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
@@ -51,7 +52,8 @@ import org.mockito.Mockito.`when` as whenever
private const val KEY = "KEY"
private const val KEY_2 = "KEY_2"
private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID"
-private const val PACKAGE_NAME = "com.android.systemui"
+private const val PACKAGE_NAME = "com.example.app"
+private const val SYSTEM_PACKAGE_NAME = "com.android.systemui"
private const val APP_NAME = "SystemUI"
private const val SESSION_ARTIST = "artist"
private const val SESSION_TITLE = "title"
@@ -92,6 +94,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Mock private lateinit var mediaRecommendationItem: SmartspaceAction
@Mock private lateinit var mediaSmartspaceBaseAction: SmartspaceAction
@Mock private lateinit var mediaFlags: MediaFlags
+ @Mock private lateinit var logger: MediaUiEventLogger
lateinit var mediaDataManager: MediaDataManager
lateinit var mediaNotification: StatusBarNotification
@Captor lateinit var mediaDataCaptor: ArgumentCaptor<MediaData>
@@ -99,6 +102,8 @@ class MediaDataManagerTest : SysuiTestCase() {
@Mock private lateinit var tunerService: TunerService
@Captor lateinit var tunableCaptor: ArgumentCaptor<TunerService.Tunable>
+ private val instanceIdSequence = InstanceIdSequenceFake(1 shl 20)
+
private val originalSmartspaceSetting = Settings.Secure.getInt(context.contentResolver,
Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, 1)
@@ -128,7 +133,8 @@ class MediaDataManagerTest : SysuiTestCase() {
useQsMediaPlayer = true,
systemClock = clock,
tunerService = tunerService,
- mediaFlags = mediaFlags
+ mediaFlags = mediaFlags,
+ logger = logger
)
verify(tunerService).addTunable(capture(tunableCaptor),
eq(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION))
@@ -169,6 +175,7 @@ class MediaDataManagerTest : SysuiTestCase() {
whenever(mediaSmartspaceTarget.iconGrid).thenReturn(listOf(mediaRecommendationItem))
whenever(mediaSmartspaceTarget.creationTimeMillis).thenReturn(1234L)
whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(false)
+ whenever(logger.getNewInstanceId()).thenReturn(instanceIdSequence.newInstanceId())
}
@After
@@ -181,15 +188,13 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testSetTimedOut_active_deactivatesMedia() {
- val data = MediaData(userId = USER_ID, initialized = true, backgroundColor = 0, app = null,
- appIcon = null, artist = null, song = null, artwork = null, actions = emptyList(),
- actionsToShowInCompact = emptyList(), packageName = "INVALID", token = null,
- clickIntent = null, device = null, active = true, resumeAction = null)
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
- mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = data)
+ addNotificationAndLoad()
+ val data = mediaDataCaptor.value
+ assertThat(data.active).isTrue()
mediaDataManager.setTimedOut(KEY, timedOut = true)
assertThat(data.active).isFalse()
+ verify(logger).logMediaTimeout(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
}
@Test
@@ -201,9 +206,15 @@ class MediaDataManagerTest : SysuiTestCase() {
}
mediaDataManager.addResumptionControls(USER_ID, desc, Runnable {}, session.sessionToken,
APP_NAME, pendingIntent, PACKAGE_NAME)
+
backgroundExecutor.runAllReady()
foregroundExecutor.runAllReady()
+ verify(listener).onMediaDataLoaded(eq(PACKAGE_NAME), eq(null), capture(mediaDataCaptor),
+ eq(true), eq(0))
+
mediaDataManager.setTimedOut(PACKAGE_NAME, timedOut = true)
+ verify(logger).logMediaTimeout(anyInt(), eq(PACKAGE_NAME),
+ eq(mediaDataCaptor.value.instanceId))
// THEN it is removed and listeners are informed
foregroundExecutor.advanceClockToLast()
@@ -219,10 +230,9 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testOnMetaDataLoaded_callsListener() {
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
- mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = mock(MediaData::class.java))
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), anyObject(), eq(true),
- eq(0))
+ addNotificationAndLoad()
+ verify(logger).logActiveMediaAdded(anyInt(), eq(PACKAGE_NAME),
+ eq(mediaDataCaptor.value.instanceId), eq(MediaData.PLAYBACK_LOCAL))
}
@Test
@@ -241,7 +251,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testOnNotificationAdded_isRcn_markedRemote() {
val rcn = SbnBuilder().run {
- setPkg("com.android.systemui") // System package
+ setPkg(SYSTEM_PACKAGE_NAME)
modifyNotification(context).also {
it.setSmallIcon(android.R.drawable.ic_media_pause)
it.setStyle(MediaStyle().apply {
@@ -259,25 +269,24 @@ class MediaDataManagerTest : SysuiTestCase() {
eq(0))
assertThat(mediaDataCaptor.value!!.playbackLocation).isEqualTo(
MediaData.PLAYBACK_CAST_REMOTE)
+ verify(logger).logActiveMediaAdded(anyInt(), eq(SYSTEM_PACKAGE_NAME),
+ eq(mediaDataCaptor.value.instanceId), eq(MediaData.PLAYBACK_CAST_REMOTE))
}
@Test
fun testOnNotificationRemoved_callsListener() {
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
- mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = mock(MediaData::class.java))
+ addNotificationAndLoad()
+ val data = mediaDataCaptor.value
mediaDataManager.onNotificationRemoved(KEY)
verify(listener).onMediaDataRemoved(eq(KEY))
+ verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
}
@Test
fun testOnNotificationRemoved_withResumption() {
// GIVEN that the manager has a notification with a resume action
whenever(controller.metadata).thenReturn(metadataBuilder.build())
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
- assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
- assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0))
+ addNotificationAndLoad()
val data = mediaDataCaptor.value
assertThat(data.resumption).isFalse()
mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
@@ -289,6 +298,7 @@ class MediaDataManagerTest : SysuiTestCase() {
eq(0))
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
+ verify(logger).logActiveConvertedToResume(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
}
@Test
@@ -333,15 +343,13 @@ class MediaDataManagerTest : SysuiTestCase() {
whenever(controller.metadata).thenReturn(metadataBuilder.build())
whenever(playbackInfo.playbackType).thenReturn(
MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE)
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
- assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
- assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0))
+ addNotificationAndLoad()
val data = mediaDataCaptor.value
val dataRemoteWithResume = data.copy(resumeAction = Runnable {},
playbackLocation = MediaData.PLAYBACK_CAST_LOCAL)
mediaDataManager.onMediaDataLoaded(KEY, null, dataRemoteWithResume)
+ verify(logger).logActiveMediaAdded(anyInt(), eq(PACKAGE_NAME),
+ eq(mediaDataCaptor.value.instanceId), eq(MediaData.PLAYBACK_CAST_LOCAL))
// WHEN the notification is removed
mediaDataManager.onNotificationRemoved(KEY)
@@ -373,12 +381,34 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(data.actions).hasSize(1)
assertThat(data.semanticActions!!.playOrPause).isNotNull()
assertThat(data.lastActive).isAtLeast(currentTime)
+ verify(logger).logResumeMediaAdded(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
+ }
+
+ @Test
+ fun testResumptionDisabled_dismissesResumeControls() {
+ // WHEN there are resume controls and resumption is switched off
+ val desc = MediaDescription.Builder().run {
+ setTitle(SESSION_TITLE)
+ build()
+ }
+ mediaDataManager.addResumptionControls(USER_ID, desc, Runnable {}, session.sessionToken,
+ APP_NAME, pendingIntent, PACKAGE_NAME)
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+ verify(listener).onMediaDataLoaded(eq(PACKAGE_NAME), eq(null), capture(mediaDataCaptor),
+ eq(true), eq(0))
+ val data = mediaDataCaptor.value
+ mediaDataManager.setMediaResumptionEnabled(false)
+
+ // THEN the resume controls are dismissed
+ verify(listener).onMediaDataRemoved(eq(PACKAGE_NAME))
+ verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
}
@Test
fun testDismissMedia_listenerCalled() {
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
- mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = mock(MediaData::class.java))
+ addNotificationAndLoad()
+ val data = mediaDataCaptor.value
val removed = mediaDataManager.dismissMediaData(KEY, 0L)
assertThat(removed).isTrue()
@@ -386,6 +416,7 @@ class MediaDataManagerTest : SysuiTestCase() {
foregroundExecutor.runAllReady()
verify(listener).onMediaDataRemoved(eq(KEY))
+ verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
}
@Test
@@ -513,11 +544,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testOnMediaDataChanged_updatesLastActiveTime() {
val currentTime = clock.elapsedRealtime()
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
- assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
- assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0))
+ addNotificationAndLoad()
assertThat(mediaDataCaptor.value!!.lastActive).isAtLeast(currentTime)
}
@@ -543,12 +570,9 @@ class MediaDataManagerTest : SysuiTestCase() {
fun testOnActiveMediaConverted_doesNotUpdateLastActiveTime() {
// GIVEN that the manager has a notification with a resume action
whenever(controller.metadata).thenReturn(metadataBuilder.build())
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
- assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
- assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0))
+ addNotificationAndLoad()
val data = mediaDataCaptor.value
+ val instanceId = data.instanceId
assertThat(data.resumption).isFalse()
mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
@@ -563,6 +587,10 @@ class MediaDataManagerTest : SysuiTestCase() {
eq(0))
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime)
+
+ // Log as a conversion event, not as a new resume control
+ verify(logger).logActiveConvertedToResume(anyInt(), eq(PACKAGE_NAME), eq(instanceId))
+ verify(logger, never()).logResumeMediaAdded(anyInt(), eq(PACKAGE_NAME), any())
}
@Test
@@ -633,11 +661,7 @@ class MediaDataManagerTest : SysuiTestCase() {
}
whenever(controller.playbackState).thenReturn(stateBuilder.build())
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
- assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
- assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0))
+ addNotificationAndLoad()
assertThat(mediaDataCaptor.value!!.semanticActions).isNotNull()
val actions = mediaDataCaptor.value!!.semanticActions!!
@@ -679,11 +703,7 @@ class MediaDataManagerTest : SysuiTestCase() {
}
whenever(controller.playbackState).thenReturn(stateBuilder.build())
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
- assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
- assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0))
+ addNotificationAndLoad()
assertThat(mediaDataCaptor.value!!.semanticActions).isNotNull()
val actions = mediaDataCaptor.value!!.semanticActions!!
@@ -722,11 +742,7 @@ class MediaDataManagerTest : SysuiTestCase() {
whenever(controller.playbackState).thenReturn(stateBuilder.build())
whenever(controller.extras).thenReturn(extras)
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
- assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
- assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0))
+ addNotificationAndLoad()
assertThat(mediaDataCaptor.value!!.semanticActions).isNotNull()
val actions = mediaDataCaptor.value!!.semanticActions!!
@@ -744,4 +760,49 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(actions.custom1).isNotNull()
assertThat(actions.custom1!!.contentDescription).isEqualTo(customDesc[1])
}
+
+ @Test
+ fun testPlaybackLocationChange_isLogged() {
+ // Media control added for local playback
+ addNotificationAndLoad()
+ val instanceId = mediaDataCaptor.value.instanceId
+
+ // Location is updated to local cast
+ whenever(controller.metadata).thenReturn(metadataBuilder.build())
+ whenever(playbackInfo.playbackType).thenReturn(
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE)
+ addNotificationAndLoad()
+ verify(logger).logPlaybackLocationChange(anyInt(), eq(PACKAGE_NAME),
+ eq(instanceId), eq(MediaData.PLAYBACK_CAST_LOCAL))
+
+ // update to remote cast
+ val rcn = SbnBuilder().run {
+ setPkg(SYSTEM_PACKAGE_NAME) // System package
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_pause)
+ it.setStyle(MediaStyle().apply {
+ setMediaSession(session.sessionToken)
+ setRemotePlaybackInfo("Remote device", 0, null)
+ })
+ }
+ build()
+ }
+
+ mediaDataManager.onNotificationAdded(KEY, rcn)
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+ verify(logger).logPlaybackLocationChange(anyInt(), eq(SYSTEM_PACKAGE_NAME),
+ eq(instanceId), eq(MediaData.PLAYBACK_CAST_REMOTE))
+ }
+
+ /**
+ * Helper function to add a media notification and capture the resulting MediaData
+ */
+ private fun addNotificationAndLoad() {
+ mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+ verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
+ eq(0))
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
index d912a8906ab3..e6f48ecd37de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
@@ -33,6 +33,7 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManager
import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManagerFactory
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -44,7 +45,6 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
-import org.mockito.Mockito
import org.mockito.Mockito.any
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
@@ -57,12 +57,8 @@ private const val KEY = "TEST_KEY"
private const val KEY_OLD = "TEST_KEY_OLD"
private const val PACKAGE = "PKG"
private const val SESSION_KEY = "SESSION_KEY"
-private const val SESSION_TITLE = "SESSION_TITLE"
private const val DEVICE_NAME = "DEVICE_NAME"
private const val REMOTE_DEVICE_NAME = "REMOTE_DEVICE_NAME"
-private const val USER_ID = 0
-
-private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -115,24 +111,9 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
// Create a media sesssion and notification for testing.
session = MediaSession(context, SESSION_KEY)
- mediaData = MediaData(
- userId = USER_ID,
- initialized = true,
- backgroundColor = 0,
- app = PACKAGE,
- appIcon = null,
- artist = null,
- song = SESSION_TITLE,
- artwork = null,
- actions = emptyList(),
- actionsToShowInCompact = emptyList(),
+ mediaData = MediaTestUtils.emptyMediaData.copy(
packageName = PACKAGE,
- token = session.sessionToken,
- clickIntent = null,
- device = null,
- active = true,
- resumeAction = null)
-
+ token = session.sessionToken)
whenever(controllerFactory.create(session.sessionToken))
.thenReturn(controller)
}
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 ceeb0dbb159e..7bd210d762f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
@@ -163,27 +163,12 @@ public class MediaPlayerDataTest : SysuiTestCase() {
isPlaying: Boolean?,
location: Int,
resumption: Boolean
- ) = MediaData(
- userId = 0,
- initialized = false,
- backgroundColor = 0,
+ ) = MediaTestUtils.emptyMediaData.copy(
app = app,
- appIcon = null,
- artist = null,
- song = null,
- artwork = null,
- actions = emptyList(),
- actionsToShowInCompact = emptyList(),
packageName = "package: $app",
- token = null,
- clickIntent = null,
- device = null,
- active = true,
- resumeAction = null,
playbackLocation = location,
resumption = resumption,
notificationKey = "key: $app",
- hasCheckedForResume = false,
isPlaying = isPlaying
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
index 30ee2e4d3431..2d34913d3467 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
@@ -24,7 +24,6 @@ import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.content.pm.ServiceInfo
-import android.graphics.Color
import android.media.MediaDescription
import android.media.session.MediaSession
import android.provider.Settings
@@ -57,13 +56,9 @@ import org.mockito.MockitoAnnotations
private const val KEY = "TEST_KEY"
private const val OLD_KEY = "RESUME_KEY"
-private const val APP = "APP"
-private const val BG_COLOR = Color.RED
private const val PACKAGE_NAME = "PKG"
private const val CLASS_NAME = "CLASS"
-private const val ARTIST = "ARTIST"
private const val TITLE = "TITLE"
-private const val USER_ID = 0
private const val MEDIA_PREFERENCES = "media_control_prefs"
private const val RESUME_COMPONENTS = "package1/class1:package2/class2:package3/class3"
@@ -130,24 +125,10 @@ class MediaResumeListenerTest : SysuiTestCase() {
resumeListener.setManager(mediaDataManager)
mediaDataManager.addListener(resumeListener)
- data = MediaData(
- userId = USER_ID,
- initialized = true,
- backgroundColor = BG_COLOR,
- app = APP,
- appIcon = null,
- artist = ARTIST,
+ data = MediaTestUtils.emptyMediaData.copy(
song = TITLE,
- artwork = null,
- actions = emptyList(),
- actionsToShowInCompact = emptyList(),
packageName = PACKAGE_NAME,
- token = token,
- clickIntent = null,
- device = device,
- active = true,
- notificationKey = KEY,
- resumeAction = null)
+ token = token)
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaSessionBasedFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaSessionBasedFilterTest.kt
index 5d53181c8345..ee4f8db48ae3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaSessionBasedFilterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaSessionBasedFilterTest.kt
@@ -16,7 +16,6 @@
package com.android.systemui.media
-import android.graphics.Color
import android.media.session.MediaController
import android.media.session.MediaController.PlaybackInfo
import android.media.session.MediaSession
@@ -39,7 +38,6 @@ import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
-import org.mockito.Mockito
import org.mockito.Mockito.any
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
@@ -50,35 +48,12 @@ import org.mockito.Mockito.`when` as whenever
private const val PACKAGE = "PKG"
private const val KEY = "TEST_KEY"
private const val NOTIF_KEY = "TEST_KEY"
-private const val SESSION_ARTIST = "SESSION_ARTIST"
-private const val SESSION_TITLE = "SESSION_TITLE"
-private const val APP_NAME = "APP_NAME"
-private const val USER_ID = 0
-
-private val info = MediaData(
- userId = USER_ID,
- initialized = true,
- backgroundColor = Color.DKGRAY,
- app = APP_NAME,
- appIcon = null,
- artist = SESSION_ARTIST,
- song = SESSION_TITLE,
- artwork = null,
- actions = emptyList(),
- actionsToShowInCompact = emptyList(),
+
+private val info = MediaTestUtils.emptyMediaData.copy(
packageName = PACKAGE,
- token = null,
- clickIntent = null,
- device = null,
- active = true,
- resumeAction = null,
- resumption = false,
- notificationKey = NOTIF_KEY,
- hasCheckedForResume = false
+ notificationKey = NOTIF_KEY
)
-private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
-
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt
new file mode 100644
index 000000000000..c7ef94eb6a64
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt
@@ -0,0 +1,27 @@
+package com.android.systemui.media
+
+import com.android.internal.logging.InstanceId
+
+class MediaTestUtils {
+ companion object {
+ val emptyMediaData = MediaData(
+ userId = 0,
+ initialized = true,
+ backgroundColor = 0,
+ app = null,
+ appIcon = null,
+ artist = null,
+ song = null,
+ artwork = null,
+ actions = emptyList(),
+ actionsToShowInCompact = emptyList(),
+ packageName = "",
+ token = null,
+ clickIntent = null,
+ device = null,
+ active = true,
+ resumeAction = null,
+ instanceId = InstanceId.fakeInstanceId(-1),
+ appUid = -1)
+ }
+} \ No newline at end of file
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 8c2fed5bd2ed..91169834752e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
@@ -25,6 +25,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -50,9 +51,7 @@ private const val PACKAGE = "PKG"
private const val SESSION_KEY = "SESSION_KEY"
private const val SESSION_ARTIST = "SESSION_ARTIST"
private const val SESSION_TITLE = "SESSION_TITLE"
-private const val USER_ID = 0
-private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
private fun <T> anyObject(): T {
return Mockito.anyObject<T>()
}
@@ -96,23 +95,11 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
}
session.setActive(true)
- mediaData = MediaData(
- userId = USER_ID,
- initialized = true,
- backgroundColor = 0,
- app = PACKAGE,
- appIcon = null,
- artist = null,
- song = SESSION_TITLE,
- artwork = null,
- actions = emptyList(),
- actionsToShowInCompact = emptyList(),
- packageName = PACKAGE,
- token = session.sessionToken,
- clickIntent = null,
- device = null,
- active = true,
- resumeAction = null)
+ mediaData = MediaTestUtils.emptyMediaData.copy(
+ app = PACKAGE,
+ packageName = PACKAGE,
+ token = session.sessionToken
+ )
resumeData = mediaData.copy(token = null, active = false, resumption = true)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
index 399c89373d63..20f5e4c19402 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
@@ -36,6 +36,7 @@ import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Ignore
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
@@ -46,6 +47,7 @@ import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
@SmallTest
@@ -71,14 +73,14 @@ public class SeekBarViewModelTest : SysuiTestCase() {
private val token1 = MediaSession.Token(1, null)
private val token2 = MediaSession.Token(2, null)
+ @JvmField @Rule val mockito = MockitoJUnit.rule()
+
@Before
fun setUp() {
fakeExecutor = FakeExecutor(FakeSystemClock())
viewModel = SeekBarViewModel(FakeRepeatableExecutor(fakeExecutor))
- viewModel.logSmartspaceClick = { }
- mockController = mock(MediaController::class.java)
+ viewModel.logSeek = { }
whenever(mockController.sessionToken).thenReturn(token1)
- mockTransport = mock(MediaController.TransportControls::class.java)
// LiveData to run synchronously
ArchTaskExecutor.getInstance().setDelegate(taskExecutor)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt
index 0787fd65eae1..e3cd90b13422 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt
@@ -8,6 +8,7 @@ import android.graphics.Rect
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
+import com.android.internal.graphics.ColorUtils
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
import com.google.common.truth.Truth.assertThat
@@ -113,6 +114,7 @@ class SquigglyProgressTest : SysuiTestCase() {
linePaintCaptor.capture())
assertThat(wavePaintCaptor.value.color).isEqualTo(tint)
- assertThat(linePaintCaptor.value.color).isEqualTo(tint)
+ assertThat(linePaintCaptor.value.color).isEqualTo(
+ ColorUtils.setAlphaComponent(tint, DISABLED_ALPHA))
}
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 534c7e7f2029..63f8641ad16d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -14,37 +14,42 @@
package com.android.systemui.qs;
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.Fragment;
import android.content.Context;
+import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.testing.AndroidTestingRunner;
-import android.testing.LayoutInflaterBuilder;
-import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import android.view.LayoutInflater;
import android.view.View;
-import android.widget.FrameLayout;
+import android.view.ViewGroup;
import androidx.test.filters.SmallTest;
-import androidx.test.filters.Suppress;
-import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
-import com.android.keyguard.CarrierText;
-import com.android.systemui.Dependency;
+import com.android.keyguard.BouncerPanelExpansionCalculator;
+import com.android.systemui.R;
import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSFragmentComponent;
import com.android.systemui.qs.external.CustomTileStatePersister;
import com.android.systemui.qs.external.TileLifecycleManager;
@@ -54,19 +59,18 @@ import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.AutoTileManager;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.animation.UniqueObjectHostView;
import com.android.systemui.util.settings.SecureSettings;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -75,77 +79,69 @@ import org.mockito.MockitoAnnotations;
import java.util.Optional;
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
@SmallTest
-@Suppress
public class QSFragmentTest extends SysuiBaseFragmentTest {
- private MetricsLogger mMockMetricsLogger;
- @Mock
- private QSFragmentComponent.Factory mQsComponentFactory;
- @Mock
- private QSFragmentComponent mQsFragmentComponent;
- @Mock
- private QSPanelController mQSPanelController;
- @Mock
- private MediaHost mQSMediaHost;
- @Mock
- private MediaHost mQQSMediaHost;
- @Mock
- private KeyguardBypassController mBypassController;
- @Mock
- private FalsingManager mFalsingManager;
- @Mock
- private TileServiceRequestController.Builder mTileServiceRequestControllerBuilder;
- @Mock
- private TileServiceRequestController mTileServiceRequestController;
+ @Mock private QSFragmentComponent.Factory mQsComponentFactory;
+ @Mock private QSFragmentComponent mQsFragmentComponent;
+ @Mock private QSPanelController mQSPanelController;
+ @Mock private MediaHost mQSMediaHost;
+ @Mock private MediaHost mQQSMediaHost;
+ @Mock private KeyguardBypassController mBypassController;
+ @Mock private FalsingManager mFalsingManager;
+ @Mock private TileServiceRequestController.Builder mTileServiceRequestControllerBuilder;
+ @Mock private TileServiceRequestController mTileServiceRequestController;
+ @Mock private QSCustomizerController mQsCustomizerController;
+ @Mock private QuickQSPanelController mQuickQSPanelController;
+ @Mock private FooterActionsController mQSFooterActionController;
+ @Mock private QSContainerImplController mQSContainerImplController;
+ @Mock private QSContainerImpl mContainer;
+ @Mock private QSFooter mFooter;
+ @Mock private LayoutInflater mLayoutInflater;
+ @Mock private NonInterceptingScrollView mQSPanelScrollView;
+ @Mock private QuickStatusBarHeader mHeader;
+ @Mock private QSPanel.QSTileLayout mQsTileLayout;
+ @Mock private QSPanel.QSTileLayout mQQsTileLayout;
+ @Mock private QSAnimator mQSAnimator;
+ @Mock private StatusBarStateController mStatusBarStateController;
+ private View mQsFragmentView;
public QSFragmentTest() {
super(QSFragment.class);
- injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
}
@Before
- @Ignore("failing")
- public void addLeakCheckDependencies() {
- MockitoAnnotations.initMocks(this);
- when(mQsComponentFactory.create(any(QSFragment.class))).thenReturn(mQsFragmentComponent);
- when(mQsFragmentComponent.getQSPanelController()).thenReturn(mQSPanelController);
-
- when(mTileServiceRequestControllerBuilder.create(any()))
- .thenReturn(mTileServiceRequestController);
-
- mMockMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
- mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE,
- new LayoutInflaterBuilder(mContext)
- .replace("com.android.systemui.statusbar.policy.SplitClockView",
- FrameLayout.class)
- .replace("TextClock", View.class)
- .replace(CarrierText.class, View.class)
- .replace(Clock.class, View.class)
- .build());
-
- mDependency.injectTestDependency(Dependency.BG_LOOPER,
- TestableLooper.get(this).getLooper());
- mDependency.injectMockDependency(UserSwitcherController.class);
+ public void setup() {
+ injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
}
@Test
- @Ignore("failing")
public void testListening() {
- assertEquals(Looper.myLooper(), Looper.getMainLooper());
QSFragment qs = (QSFragment) mFragment;
mFragments.dispatchResume();
processAllMessages();
- QSTileHost host = new QSTileHost(mContext, mock(StatusBarIconController.class),
- mock(QSFactoryImpl.class), new Handler(), Looper.myLooper(),
- mock(PluginManager.class), mock(TunerService.class),
- () -> mock(AutoTileManager.class), mock(DumpManager.class),
- mock(BroadcastDispatcher.class), Optional.of(mock(CentralSurfaces.class)),
- mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class),
- mock(SecureSettings.class), mock(CustomTileStatePersister.class),
- mTileServiceRequestControllerBuilder, mock(TileLifecycleManager.Factory.class));
+ QSTileHost host =
+ new QSTileHost(
+ mContext,
+ mock(StatusBarIconController.class),
+ mock(QSFactoryImpl.class),
+ new Handler(),
+ Looper.myLooper(),
+ mock(PluginManager.class),
+ mock(TunerService.class),
+ () -> mock(AutoTileManager.class),
+ mock(DumpManager.class),
+ mock(BroadcastDispatcher.class),
+ Optional.of(mock(CentralSurfaces.class)),
+ mock(QSLogger.class),
+ mock(UiEventLogger.class),
+ mock(UserTracker.class),
+ mock(SecureSettings.class),
+ mock(CustomTileStatePersister.class),
+ mTileServiceRequestControllerBuilder,
+ mock(TileLifecycleManager.Factory.class));
qs.setListening(true);
processAllMessages();
@@ -157,13 +153,11 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
}
@Test
- @Ignore("failing")
public void testSaveState() {
- QSFragment qs = (QSFragment) mFragment;
-
mFragments.dispatchResume();
processAllMessages();
+ QSFragment qs = (QSFragment) mFragment;
qs.setListening(true);
qs.setExpanded(true);
processAllMessages();
@@ -176,14 +170,156 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
assertTrue(qs.isExpanded());
}
+ @Test
+ public void transitionToFullShade_inSplitShade_setsAlphaBasedOnProgress() {
+ QSFragment fragment = resumeAndGetFragment();
+ enableSplitShade();
+ int transitionPxAmount = 123;
+ float transitionProgress = 0.5f;
+
+ fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+
+ assertThat(mQsFragmentView.getAlpha())
+ .isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress));
+ }
+
+ @Test
+ public void
+ transitionToFullShade_inSplitShade_onKeyguard_bouncerNotActive_usesShadeInterpolator() {
+ QSFragment fragment = resumeAndGetFragment();
+ enableSplitShade();
+ setStatusBarState(StatusBarState.KEYGUARD);
+ when(mQSPanelController.bouncerInTransit()).thenReturn(false);
+ int transitionPxAmount = 123;
+ float transitionProgress = 0.5f;
+
+ fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+
+ assertThat(mQsFragmentView.getAlpha())
+ .isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress));
+ }
+
+ @Test
+ public void
+ transitionToFullShade_inSplitShade_onKeyguard_bouncerActive_usesBouncerInterpolator() {
+ QSFragment fragment = resumeAndGetFragment();
+ enableSplitShade();
+ setStatusBarState(StatusBarState.KEYGUARD);
+ when(mQSPanelController.bouncerInTransit()).thenReturn(true);
+ int transitionPxAmount = 123;
+ float transitionProgress = 0.5f;
+
+ fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+
+ assertThat(mQsFragmentView.getAlpha())
+ .isEqualTo(
+ BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(
+ transitionProgress));
+ }
+
+ @Test
+ public void transitionToFullShade_notInSplitShade_alwaysSetsAlphaTo1() {
+ QSFragment fragment = resumeAndGetFragment();
+ disableSplitShade();
+
+ int transitionPxAmount = 12;
+ float transitionProgress = 0.1f;
+ fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+ assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
+
+ transitionPxAmount = 123;
+ transitionProgress = 0.5f;
+ fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+ assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
+ assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
+
+ transitionPxAmount = 234;
+ transitionProgress = 0.7f;
+ fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+ assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
+ }
+
+ @Test
+ public void getQsMinExpansionHeight_notInSplitShade_returnsHeaderHeight() {
+ QSFragment fragment = resumeAndGetFragment();
+ disableSplitShade();
+ when(mHeader.getHeight()).thenReturn(1234);
+
+ int height = fragment.getQsMinExpansionHeight();
+
+ assertThat(height).isEqualTo(mHeader.getHeight());
+ }
+
+ @Test
+ public void getQsMinExpansionHeight_inSplitShade_returnsAbsoluteBottomOfQSContainer() {
+ int top = 1234;
+ int height = 9876;
+ QSFragment fragment = resumeAndGetFragment();
+ enableSplitShade();
+ setLocationOnScreen(mQsFragmentView, top);
+ when(mQsFragmentView.getHeight()).thenReturn(height);
+
+ int expectedHeight = top + height;
+ assertThat(fragment.getQsMinExpansionHeight()).isEqualTo(expectedHeight);
+ }
+
+ @Test
+ public void getQsMinExpansionHeight_inSplitShade_returnsAbsoluteBottomExcludingTranslation() {
+ int top = 1234;
+ int height = 9876;
+ float translationY = -600f;
+ QSFragment fragment = resumeAndGetFragment();
+ enableSplitShade();
+ setLocationOnScreen(mQsFragmentView, (int) (top + translationY));
+ when(mQsFragmentView.getHeight()).thenReturn(height);
+ when(mQsFragmentView.getTranslationY()).thenReturn(translationY);
+
+ int expectedHeight = top + height;
+ assertThat(fragment.getQsMinExpansionHeight()).isEqualTo(expectedHeight);
+ }
+
+ @Test
+ public void hideImmediately_notInSplitShade_movesViewUpByHeaderHeight() {
+ QSFragment fragment = resumeAndGetFragment();
+ disableSplitShade();
+ when(mHeader.getHeight()).thenReturn(555);
+
+ fragment.hideImmediately();
+
+ assertThat(mQsFragmentView.getY()).isEqualTo(-mHeader.getHeight());
+ }
+
+ @Test
+ public void hideImmediately_inSplitShade_movesViewUpByQSAbsoluteBottom() {
+ QSFragment fragment = resumeAndGetFragment();
+ enableSplitShade();
+ int top = 1234;
+ int height = 9876;
+ setLocationOnScreen(mQsFragmentView, top);
+ when(mQsFragmentView.getHeight()).thenReturn(height);
+
+ fragment.hideImmediately();
+
+ int qsAbsoluteBottom = top + height;
+ assertThat(mQsFragmentView.getY()).isEqualTo(-qsAbsoluteBottom);
+ }
+
@Override
protected Fragment instantiate(Context context, String className, Bundle arguments) {
+ MockitoAnnotations.initMocks(this);
CommandQueue commandQueue = new CommandQueue(context);
+
+ setupQsComponent();
+ setUpViews();
+ setUpInflater();
+ setUpMedia();
+ setUpOther();
+
return new QSFragment(
- new RemoteInputQuickSettingsDisabler(context, commandQueue,
- mock(ConfigurationController.class)),
+ new RemoteInputQuickSettingsDisabler(
+ context, commandQueue, mock(ConfigurationController.class)),
mock(QSTileHost.class),
- mock(StatusBarStateController.class),
+ mStatusBarStateController,
commandQueue,
mQSMediaHost,
mQQSMediaHost,
@@ -193,4 +329,82 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
mFalsingManager,
mock(DumpManager.class));
}
+
+ private void setUpOther() {
+ when(mTileServiceRequestControllerBuilder.create(any()))
+ .thenReturn(mTileServiceRequestController);
+ when(mQSContainerImplController.getView()).thenReturn(mContainer);
+ when(mQSPanelController.getTileLayout()).thenReturn(mQQsTileLayout);
+ when(mQuickQSPanelController.getTileLayout()).thenReturn(mQsTileLayout);
+ }
+
+ private void setUpMedia() {
+ when(mQSMediaHost.getCurrentClipping()).thenReturn(new Rect());
+ when(mQSMediaHost.getHostView()).thenReturn(new UniqueObjectHostView(mContext));
+ when(mQQSMediaHost.getHostView()).thenReturn(new UniqueObjectHostView(mContext));
+ }
+
+ private void setUpViews() {
+ mQsFragmentView = spy(new View(mContext));
+ when(mQsFragmentView.findViewById(R.id.expanded_qs_scroll_view))
+ .thenReturn(mQSPanelScrollView);
+ when(mQsFragmentView.findViewById(R.id.header)).thenReturn(mHeader);
+ when(mQsFragmentView.findViewById(android.R.id.edit)).thenReturn(new View(mContext));
+ }
+
+ private void setUpInflater() {
+ when(mLayoutInflater.cloneInContext(any(Context.class))).thenReturn(mLayoutInflater);
+ when(mLayoutInflater.inflate(anyInt(), any(ViewGroup.class), anyBoolean()))
+ .thenReturn(mQsFragmentView);
+ mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, mLayoutInflater);
+ }
+
+ private void setupQsComponent() {
+ when(mQsComponentFactory.create(any(QSFragment.class))).thenReturn(mQsFragmentComponent);
+ when(mQsFragmentComponent.getQSPanelController()).thenReturn(mQSPanelController);
+ when(mQsFragmentComponent.getQuickQSPanelController()).thenReturn(mQuickQSPanelController);
+ when(mQsFragmentComponent.getQSCustomizerController()).thenReturn(mQsCustomizerController);
+ when(mQsFragmentComponent.getQSContainerImplController())
+ .thenReturn(mQSContainerImplController);
+ when(mQsFragmentComponent.getQSFooter()).thenReturn(mFooter);
+ when(mQsFragmentComponent.getQSFooterActionController())
+ .thenReturn(mQSFooterActionController);
+ when(mQsFragmentComponent.getQSAnimator()).thenReturn(mQSAnimator);
+ }
+
+ private QSFragment getFragment() {
+ return ((QSFragment) mFragment);
+ }
+
+ private QSFragment resumeAndGetFragment() {
+ mFragments.dispatchResume();
+ processAllMessages();
+ return getFragment();
+ }
+
+ private void setStatusBarState(int statusBarState) {
+ when(mStatusBarStateController.getState()).thenReturn(statusBarState);
+ getFragment().onStateChanged(statusBarState);
+ }
+
+ private void enableSplitShade() {
+ setSplitShadeEnabled(true);
+ }
+
+ private void disableSplitShade() {
+ setSplitShadeEnabled(false);
+ }
+
+ private void setSplitShadeEnabled(boolean enabled) {
+ getFragment().setInSplitShade(enabled);
+ }
+
+ private void setLocationOnScreen(View view, int top) {
+ doAnswer(invocation -> {
+ int[] locationOnScreen = invocation.getArgument(/* index= */ 0);
+ locationOnScreen[0] = 0;
+ locationOnScreen[1] = top;
+ return null;
+ }).when(view).getLocationOnScreen(any(int[].class));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
index e9488e9ad98c..58a070db9a95 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
@@ -15,7 +15,9 @@ import com.android.systemui.qs.customize.QSCustomizerController
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.settings.brightness.BrightnessController
import com.android.systemui.settings.brightness.BrightnessSliderController
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.tuner.TunerService
+import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -52,6 +54,7 @@ class QSPanelControllerTest : SysuiTestCase() {
@Mock private lateinit var mediaHost: MediaHost
@Mock private lateinit var tile: QSTile
@Mock private lateinit var otherTile: QSTile
+ @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
private lateinit var controller: QSPanelController
@@ -62,6 +65,7 @@ class QSPanelControllerTest : SysuiTestCase() {
whenever(brightnessSliderFactory.create(any(), any())).thenReturn(brightnessSlider)
whenever(brightnessControllerFactory.create(any())).thenReturn(brightnessController)
whenever(qsPanel.resources).thenReturn(mContext.orCreateTestableResources.resources)
+ whenever(statusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(false)
controller = QSPanelController(
qsPanel,
@@ -80,7 +84,8 @@ class QSPanelControllerTest : SysuiTestCase() {
brightnessControllerFactory,
brightnessSliderFactory,
falsingManager,
- featureFlags
+ featureFlags,
+ statusBarKeyguardViewManager
)
}
@@ -109,4 +114,12 @@ class QSPanelControllerTest : SysuiTestCase() {
verify(tile).refreshState()
verify(otherTile, Mockito.never()).refreshState()
}
+
+ @Test
+ fun testBouncerIsInTransit() {
+ whenever(statusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(true)
+ assertThat(controller.bouncerInTransit()).isEqualTo(true)
+ whenever(statusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(false)
+ assertThat(controller.bouncerInTransit()).isEqualTo(false)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index 6abdea5d9230..bc1abe62c7ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -25,6 +25,8 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -87,4 +89,42 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {
controller.setDozeAmount(0.5f, false /* animated */)
verify(listener).onDozeAmountChanged(eq(0.5f), anyFloat())
}
+
+ @Test
+ fun testSetState_appliesState_sameStateButDifferentUpcomingState() {
+ controller.state = StatusBarState.SHADE
+ controller.setUpcomingState(StatusBarState.KEYGUARD)
+
+ assertEquals(controller.state, StatusBarState.SHADE)
+
+ // We should return true (state change was applied) despite going from SHADE to SHADE, since
+ // the upcoming state was set to KEYGUARD.
+ assertTrue(controller.setState(StatusBarState.SHADE))
+ }
+
+ @Test
+ fun testSetState_appliesState_differentStateEqualToUpcomingState() {
+ controller.state = StatusBarState.SHADE
+ controller.setUpcomingState(StatusBarState.KEYGUARD)
+
+ assertEquals(controller.state, StatusBarState.SHADE)
+
+ // Make sure we apply a SHADE -> KEYGUARD state change when the upcoming state is KEYGUARD.
+ assertTrue(controller.setState(StatusBarState.KEYGUARD))
+ }
+
+ @Test
+ fun testSetState_doesNotApplyState_currentAndUpcomingStatesSame() {
+ controller.state = StatusBarState.SHADE
+ controller.setUpcomingState(StatusBarState.SHADE)
+
+ assertEquals(controller.state, StatusBarState.SHADE)
+
+ // We're going from SHADE -> SHADE, and the upcoming state is also SHADE, this should not do
+ // anything.
+ assertFalse(controller.setState(StatusBarState.SHADE))
+
+ // Double check that we can still force it to happen.
+ assertTrue(controller.setState(StatusBarState.SHADE, true /* force */))
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index 5f2bbd341962..077b41a0aa90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -126,6 +126,12 @@ public class DozeParametersTest extends SysuiTestCase {
setAodEnabledForTest(true);
setShouldControlUnlockedScreenOffForTest(true);
setDisplayNeedsBlankingForTest(false);
+
+ // Default to false here (with one test to make sure that when it returns true, we respect
+ // that). We'll test the specific conditions for this to return true/false in the
+ // UnlockedScreenOffAnimationController's tests.
+ when(mUnlockedScreenOffAnimationController.shouldPlayUnlockedScreenOffAnimation())
+ .thenReturn(false);
}
@Test
@@ -174,9 +180,12 @@ public class DozeParametersTest extends SysuiTestCase {
*/
@Test
public void testControlUnlockedScreenOffAnimation_dozeAfterScreenOff_false() {
+ mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(true);
+
// If AOD is disabled, we shouldn't want to control screen off. Also, let's double check
// that when that value is updated, we called through to PowerManager.
setAodEnabledForTest(false);
+
assertFalse(mDozeParameters.shouldControlScreenOff());
assertTrue(mPowerManagerDozeAfterScreenOff);
@@ -188,7 +197,6 @@ public class DozeParametersTest extends SysuiTestCase {
@Test
public void testControlUnlockedScreenOffAnimationDisabled_dozeAfterScreenOff() {
- setShouldControlUnlockedScreenOffForTest(true);
when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)).thenReturn(false);
assertFalse(mDozeParameters.shouldControlUnlockedScreenOff());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 5eef1df8c7a3..b3f8f9114021 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -119,7 +119,8 @@ public class ScrimControllerTest extends SysuiTestCase {
// event-dispatch-on-registration pattern caused some of these unit tests to fail.)
@Mock
private PanelExpansionStateManager mPanelExpansionStateManager;
-
+ @Mock
+ private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private static class AnimatorListener implements Animator.AnimatorListener {
private int mNumStarts;
@@ -233,7 +234,8 @@ public class ScrimControllerTest extends SysuiTestCase {
mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
mScreenOffAnimationController,
mPanelExpansionStateManager,
- mKeyguardUnlockAnimationController);
+ mKeyguardUnlockAnimationController,
+ mStatusBarKeyguardViewManager);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
@@ -1234,6 +1236,8 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void testNotificationTransparency_followsPanelExpansionInShadeLockedState() {
+ when(mStatusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(true);
+
mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0f, /* expansion */ 0.8f);
@@ -1242,6 +1246,8 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void testNotificationTransparency_unnocclusion() {
+ when(mStatusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(true);
+
mScrimController.transitionTo(ScrimState.KEYGUARD);
mScrimController.setUnocclusionAnimationRunning(true);
@@ -1255,6 +1261,8 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void testNotificationTransparency_inKeyguardState() {
+ when(mStatusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(true);
+
mScrimController.transitionTo(ScrimState.KEYGUARD);
assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 1f, /* expansion */ 0.8f);
@@ -1351,6 +1359,30 @@ public class ScrimControllerTest extends SysuiTestCase {
));
}
+ @Test
+ public void keyguardGoingAwayUpdateScrims() {
+ when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true);
+ mScrimController.updateScrims();
+ finishAnimationsImmediately();
+ assertThat(mNotificationsScrim.getViewAlpha()).isEqualTo(TRANSPARENT);
+ }
+
+
+ @Test
+ public void setUnOccludingAnimationKeyguard() {
+ mScrimController.setUnocclusionAnimationRunning(true);
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ finishAnimationsImmediately();
+ assertThat(mNotificationsScrim.getViewAlpha())
+ .isWithin(0.01f).of(ScrimState.KEYGUARD.getNotifAlpha());
+ assertThat(mNotificationsScrim.getTint())
+ .isEqualTo(ScrimState.KEYGUARD.getNotifTint());
+ assertThat(mScrimBehind.getViewAlpha())
+ .isWithin(0.01f).of(ScrimState.KEYGUARD.getBehindAlpha());
+ assertThat(mScrimBehind.getTint())
+ .isEqualTo(ScrimState.KEYGUARD.getBehindTint());
+ }
+
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
mScrimController.setRawPanelExpansionFraction(expansion);
finishAnimationsImmediately();
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 ede3de83b572..90cbf540004e 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
@@ -55,6 +55,8 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.unfold.SysUIUnfoldComponent;
+import com.google.common.truth.Truth;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -434,4 +436,14 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
verify(mBouncer).updateKeyguardPosition(1.0f);
}
+
+ @Test
+ public void testBouncerIsInTransit() {
+ when(mBouncer.inTransit()).thenReturn(true);
+ Truth.assertThat(mStatusBarKeyguardViewManager.bouncerIsInTransit()).isTrue();
+ when(mBouncer.inTransit()).thenReturn(false);
+ Truth.assertThat(mStatusBarKeyguardViewManager.bouncerIsInTransit()).isFalse();
+ mBouncer = null;
+ Truth.assertThat(mStatusBarKeyguardViewManager.bouncerIsInTransit()).isFalse();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
index 050563a5707c..0936b773d4b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
@@ -31,6 +31,7 @@ import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.StatusBarStateControllerImpl
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.settings.GlobalSettings
+import junit.framework.Assert.assertFalse
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -133,7 +134,7 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() {
*/
@Test
fun testAodUiShownIfNotInteractive() {
- `when`(dozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true)
+ `when`(dozeParameters.canControlUnlockedScreenOff()).thenReturn(true)
`when`(powerManager.isInteractive).thenReturn(false)
val callbackCaptor = ArgumentCaptor.forClass(Runnable::class.java)
@@ -156,7 +157,7 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() {
*/
@Test
fun testAodUiNotShownIfInteractive() {
- `when`(dozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true)
+ `when`(dozeParameters.canControlUnlockedScreenOff()).thenReturn(true)
`when`(powerManager.isInteractive).thenReturn(true)
val callbackCaptor = ArgumentCaptor.forClass(Runnable::class.java)
@@ -167,4 +168,13 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() {
verify(notificationPanelViewController, never()).showAodUi()
}
+
+ @Test
+ fun testNoAnimationPlaying_dozeParamsCanNotControlScreenOff() {
+ `when`(dozeParameters.canControlUnlockedScreenOff()).thenReturn(false)
+
+ assertFalse(controller.shouldPlayUnlockedScreenOffAnimation())
+ controller.startAnimation()
+ assertFalse(controller.isAnimationPlaying())
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
index 12cfb32ab57e..14e087846417 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
@@ -51,7 +51,7 @@ import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.DeviceConfigProxyFake;
-import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.settings.FakeSettings;
import com.google.common.collect.ImmutableList;
@@ -70,11 +70,11 @@ public class LocationControllerImplTest extends SysuiTestCase {
private TestableLooper mTestableLooper;
private DeviceConfigProxy mDeviceConfigProxy;
private UiEventLoggerFake mUiEventLogger;
+ private FakeSettings mSecureSettings;
@Mock private PackageManager mPackageManager;
@Mock private AppOpsController mAppOpsController;
@Mock private UserTracker mUserTracker;
- @Mock private SecureSettings mSecureSettings;
@Before
public void setup() {
@@ -85,7 +85,7 @@ public class LocationControllerImplTest extends SysuiTestCase {
.thenReturn(ImmutableList.of(new UserInfo(0, "name", 0)));
mDeviceConfigProxy = new DeviceConfigProxyFake();
mUiEventLogger = new UiEventLoggerFake();
-
+ mSecureSettings = new FakeSettings();
mTestableLooper = TestableLooper.get(this);
mLocationController = new LocationControllerImpl(mContext,
@@ -248,8 +248,7 @@ public class LocationControllerImplTest extends SysuiTestCase {
@Test
public void testCallbackNotified_additionalOps_shouldShowSystem() {
- when(mSecureSettings.getInt(Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 0))
- .thenReturn(1);
+ mSecureSettings.putInt(Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 1);
LocationChangeCallback callback = mock(LocationChangeCallback.class);
mLocationController.addCallback(callback);
mDeviceConfigProxy.setProperty(
@@ -282,8 +281,7 @@ public class LocationControllerImplTest extends SysuiTestCase {
verify(callback, times(1)).onLocationActiveChanged(false);
- when(mSecureSettings.getInt(Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 0))
- .thenReturn(0);
+ mSecureSettings.putInt(Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 0);
mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
"com.system.app", true);
@@ -367,4 +365,46 @@ public class LocationControllerImplTest extends SysuiTestCase {
// No new callbacks
verify(callback).onLocationSettingsChanged(anyBoolean());
}
+
+ @Test
+ public void testExperimentFlipsSystemFlag() throws Exception {
+ mSecureSettings.putInt(Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 0);
+ mDeviceConfigProxy.setProperty(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED,
+ "true",
+ true);
+ // Show system experiment not running
+ mDeviceConfigProxy.setProperty(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SHOW_SYSTEM,
+ "false",
+ false);
+ mTestableLooper.processAllMessages();
+
+ // Flip experiment on
+ mDeviceConfigProxy.setProperty(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SHOW_SYSTEM,
+ "true",
+ true);
+ mTestableLooper.processAllMessages();
+
+ // Verify settings were flipped
+ assertThat(mSecureSettings.getInt(Settings.Secure.LOCATION_SHOW_SYSTEM_OPS))
+ .isEqualTo(1);
+ assertThat(mSecureSettings.getInt(Settings.Secure.LOCATION_INDICATOR_EXPERIMENT_STARTED))
+ .isEqualTo(1);
+
+ // Flip experiment off
+ mDeviceConfigProxy.setProperty(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SHOW_SYSTEM,
+ "false",
+ false);
+ mTestableLooper.processAllMessages();
+
+ assertThat(mSecureSettings.getInt(Settings.Secure.LOCATION_INDICATOR_EXPERIMENT_STARTED))
+ .isEqualTo(0);
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 78ee9e8921ea..ca67bd2d6fca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -70,6 +70,7 @@ import android.service.notification.NotificationListenerService;
import android.service.notification.ZenModeConfig;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.View;
import android.view.WindowManager;
import androidx.test.filters.SmallTest;
@@ -377,7 +378,7 @@ public class BubblesTest extends SysuiTestCase {
mContext,
mBubbleController.asBubbles(),
mNotificationShadeWindowController,
- mStatusBarStateController,
+ mock(KeyguardStateController.class),
mShadeController,
mConfigurationController,
mStatusBarService,
@@ -1427,6 +1428,23 @@ public class BubblesTest extends SysuiTestCase {
assertStackCollapsed();
}
+ @Test
+ public void testOnStatusBarStateChanged() {
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleData.setExpanded(true);
+ assertStackExpanded();
+ BubbleStackView stackView = mBubbleController.getStackView();
+ assertThat(stackView.getVisibility()).isEqualTo(View.VISIBLE);
+
+ mBubbleController.onStatusBarStateChanged(false);
+
+ assertStackCollapsed();
+ assertThat(stackView.getVisibility()).isEqualTo(View.INVISIBLE);
+
+ mBubbleController.onStatusBarStateChanged(true);
+ assertThat(stackView.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
/** Creates a bubble using the userId and package. */
private Bubble createBubble(int userId, String pkg) {
final UserHandle userHandle = new UserHandle(userId);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index fafe4b3fdb5f..40657fb61412 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -59,6 +59,7 @@ import android.service.notification.NotificationListenerService;
import android.service.notification.ZenModeConfig;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.View;
import android.view.WindowManager;
import androidx.test.filters.SmallTest;
@@ -342,7 +343,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mContext,
mBubbleController.asBubbles(),
mNotificationShadeWindowController,
- mStatusBarStateController,
+ mock(KeyguardStateController.class),
mShadeController,
mConfigurationController,
mStatusBarService,
@@ -1247,6 +1248,23 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
assertStackCollapsed();
}
+ @Test
+ public void testOnStatusBarStateChanged() {
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleData.setExpanded(true);
+ assertStackExpanded();
+ BubbleStackView stackView = mBubbleController.getStackView();
+ assertThat(stackView.getVisibility()).isEqualTo(View.VISIBLE);
+
+ mBubbleController.onStatusBarStateChanged(false);
+
+ assertStackCollapsed();
+ assertThat(stackView.getVisibility()).isEqualTo(View.INVISIBLE);
+
+ mBubbleController.onStatusBarStateChanged(true);
+ assertThat(stackView.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
/**
* Sets the bubble metadata flags for this entry. These flags are normally set by
* NotificationManagerService when the notification is sent, however, these tests do not
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 75b6554a013b..7e277ba3c0d0 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -3182,7 +3182,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
@Override
public void onFillReady(@NonNull FillResponse response, @NonNull AutofillId filledId,
- @Nullable AutofillValue value) {
+ @Nullable AutofillValue value, int flags) {
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onFillReady() rejected - session: "
@@ -3207,7 +3207,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return;
}
- if (requestShowFillDialog(response, filledId, filterText)) {
+ if (requestShowFillDialog(response, filledId, filterText, flags)) {
synchronized (mLock) {
final ViewState currentView = mViewStates.get(mCurrentViewId);
currentView.setState(ViewState.STATE_FILL_DIALOG_SHOWN);
@@ -3312,12 +3312,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
private boolean requestShowFillDialog(FillResponse response,
- AutofillId filledId, String filterText) {
+ AutofillId filledId, String filterText, int flags) {
if (!isFillDialogUiEnabled()) {
// Unsupported fill dialog UI
return false;
}
+ if ((flags & FillRequest.FLAG_IME_SHOWING) != 0) {
+ // IME is showing, fallback to normal suggestions UI
+ return false;
+ }
+
final AutofillId[] ids = response.getFillDialogTriggerIds();
if (ids == null || !ArrayUtils.contains(ids, filledId)) {
return false;
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 4a14f1420cf2..12695ac6ad35 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -43,7 +43,7 @@ final class ViewState {
* Called when the fill UI is ready to be shown for this view.
*/
void onFillReady(@NonNull FillResponse fillResponse, @NonNull AutofillId focusedId,
- @Nullable AutofillValue value);
+ @Nullable AutofillValue value, int flags);
}
private static final String TAG = "ViewState";
@@ -202,7 +202,7 @@ final class ViewState {
/**
* Calls {@link
- * Listener#onFillReady(FillResponse, AutofillId, AutofillValue)} if the
+ * Listener#onFillReady(FillResponse, AutofillId, AutofillValue, int)} if the
* fill UI is ready to be displayed (i.e. when response and bounds are set).
*/
void maybeCallOnFillReady(int flags) {
@@ -213,7 +213,7 @@ final class ViewState {
// First try the current response associated with this View.
if (mResponse != null) {
if (mResponse.getDatasets() != null || mResponse.getAuthentication() != null) {
- mListener.onFillReady(mResponse, this.id, mCurrentValue);
+ mListener.onFillReady(mResponse, this.id, mCurrentValue, flags);
}
}
}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 06fd5c0e9b82..e4b839af8b2e 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -23,6 +23,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.StringRes;
import android.app.Activity;
@@ -32,9 +33,11 @@ import android.app.admin.DevicePolicyManager;
import android.companion.AssociationInfo;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceActivityListener;
+import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceManager.ActivityListener;
import android.companion.virtual.VirtualDeviceParams;
-import android.companion.virtual.audio.IAudioSessionCallback;
+import android.companion.virtual.audio.IAudioConfigChangedCallback;
+import android.companion.virtual.audio.IAudioRoutingCallback;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -77,6 +80,12 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
implements IBinder.DeathRecipient {
private static final String TAG = "VirtualDeviceImpl";
+
+ /**
+ * Timeout until {@link #launchPendingIntent} stops waiting for an activity to be launched.
+ */
+ private static final long PENDING_TRAMPOLINE_TIMEOUT_MS = 5000;
+
private final Object mVirtualDeviceLock = new Object();
private final Context mContext;
@@ -193,20 +202,27 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
if (pendingIntent.isActivity()) {
try {
sendPendingIntent(displayId, pendingIntent);
- resultReceiver.send(Activity.RESULT_OK, null);
+ resultReceiver.send(VirtualDeviceManager.LAUNCH_SUCCESS, null);
} catch (PendingIntent.CanceledException e) {
Slog.w(TAG, "Pending intent canceled", e);
- resultReceiver.send(Activity.RESULT_CANCELED, null);
+ resultReceiver.send(
+ VirtualDeviceManager.LAUNCH_FAILURE_PENDING_INTENT_CANCELED, null);
}
} else {
PendingTrampoline pendingTrampoline = new PendingTrampoline(pendingIntent,
resultReceiver, displayId);
mPendingTrampolineCallback.startWaitingForPendingTrampoline(pendingTrampoline);
+ mContext.getMainThreadHandler().postDelayed(() -> {
+ pendingTrampoline.mResultReceiver.send(
+ VirtualDeviceManager.LAUNCH_FAILURE_NO_ACTIVITY, null);
+ mPendingTrampolineCallback.stopWaitingForPendingTrampoline(pendingTrampoline);
+ }, PENDING_TRAMPOLINE_TIMEOUT_MS);
try {
sendPendingIntent(displayId, pendingIntent);
} catch (PendingIntent.CanceledException e) {
Slog.w(TAG, "Pending intent canceled", e);
- resultReceiver.send(Activity.RESULT_CANCELED, null);
+ resultReceiver.send(
+ VirtualDeviceManager.LAUNCH_FAILURE_PENDING_INTENT_CANCELED, null);
mPendingTrampolineCallback.stopWaitingForPendingTrampoline(pendingTrampoline);
}
}
@@ -269,7 +285,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@Override // Binder call
- public void onAudioSessionStarting(int displayId, IAudioSessionCallback callback) {
+ public void onAudioSessionStarting(int displayId,
+ @NonNull IAudioRoutingCallback routingCallback,
+ @Nullable IAudioConfigChangedCallback configChangedCallback) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
"Permission required to start audio session");
@@ -283,7 +301,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
if (mVirtualAudioController == null) {
mVirtualAudioController = new VirtualAudioController(mContext);
GenericWindowPolicyController gwpc = mWindowPolicyControllers.get(displayId);
- mVirtualAudioController.startListening(gwpc, callback);
+ mVirtualAudioController.startListening(gwpc, routingCallback,
+ configChangedCallback);
}
}
}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 96400c1414ec..9acca8025920 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -21,7 +21,6 @@ import static com.android.server.wm.ActivityInterceptorCallback.VIRTUAL_DEVICE_S
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
-import android.app.Activity;
import android.app.ActivityOptions;
import android.companion.AssociationInfo;
import android.companion.CompanionDeviceManager;
@@ -29,6 +28,7 @@ import android.companion.CompanionDeviceManager.OnAssociationsChangedListener;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceActivityListener;
import android.companion.virtual.IVirtualDeviceManager;
+import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceParams;
import android.content.Context;
import android.os.Handler;
@@ -64,7 +64,7 @@ public class VirtualDeviceManagerService extends SystemService {
private final Object mVirtualDeviceManagerLock = new Object();
private final VirtualDeviceManagerImpl mImpl;
- private VirtualDeviceManagerInternal mLocalService;
+ private final VirtualDeviceManagerInternal mLocalService;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final PendingTrampolineMap mPendingTrampolines = new PendingTrampolineMap(mHandler);
/**
@@ -115,7 +115,7 @@ public class VirtualDeviceManagerService extends SystemService {
if (pt == null) {
return null;
}
- pt.mResultReceiver.send(Activity.RESULT_OK, null);
+ pt.mResultReceiver.send(VirtualDeviceManager.LAUNCH_SUCCESS, null);
ActivityOptions options = info.checkedOptions;
if (options == null) {
options = ActivityOptions.makeBasic();
@@ -314,7 +314,8 @@ public class VirtualDeviceManagerService extends SystemService {
pendingTrampoline.mPendingIntent.getCreatorPackage(),
pendingTrampoline);
if (existing != null) {
- existing.mResultReceiver.send(Activity.RESULT_CANCELED, null);
+ existing.mResultReceiver.send(
+ VirtualDeviceManager.LAUNCH_FAILURE_NO_ACTIVITY, null);
}
}
diff --git a/services/companion/java/com/android/server/companion/virtual/audio/AudioPlaybackDetector.java b/services/companion/java/com/android/server/companion/virtual/audio/AudioPlaybackDetector.java
index 2d7291300e23..6e82d6672cd4 100644
--- a/services/companion/java/com/android/server/companion/virtual/audio/AudioPlaybackDetector.java
+++ b/services/companion/java/com/android/server/companion/virtual/audio/AudioPlaybackDetector.java
@@ -51,8 +51,10 @@ final class AudioPlaybackDetector extends AudioManager.AudioPlaybackCallback {
}
void unregister() {
- mAudioPlaybackCallback = null;
- mAudioManager.unregisterAudioPlaybackCallback(/* cb= */ this);
+ if (mAudioPlaybackCallback != null) {
+ mAudioPlaybackCallback = null;
+ mAudioManager.unregisterAudioPlaybackCallback(/* cb= */ this);
+ }
}
@Override
diff --git a/services/companion/java/com/android/server/companion/virtual/audio/AudioRecordingDetector.java b/services/companion/java/com/android/server/companion/virtual/audio/AudioRecordingDetector.java
index c20414529f5b..54add2e1fc85 100644
--- a/services/companion/java/com/android/server/companion/virtual/audio/AudioRecordingDetector.java
+++ b/services/companion/java/com/android/server/companion/virtual/audio/AudioRecordingDetector.java
@@ -51,8 +51,10 @@ final class AudioRecordingDetector extends AudioManager.AudioRecordingCallback {
}
void unregister() {
- mAudioRecordingCallback = null;
- mAudioManager.unregisterAudioRecordingCallback(/* cb= */ this);
+ if (mAudioRecordingCallback != null) {
+ mAudioRecordingCallback = null;
+ mAudioManager.unregisterAudioRecordingCallback(/* cb= */ this);
+ }
}
@Override
diff --git a/services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java b/services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java
index 1dc87d68aeae..13a47d681729 100644
--- a/services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java
+++ b/services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java
@@ -21,7 +21,8 @@ import static android.media.AudioPlaybackConfiguration.PLAYER_STATE_STARTED;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
-import android.companion.virtual.audio.IAudioSessionCallback;
+import android.companion.virtual.audio.IAudioConfigChangedCallback;
+import android.companion.virtual.audio.IAudioRoutingCallback;
import android.content.Context;
import android.media.AudioManager;
import android.media.AudioPlaybackConfiguration;
@@ -64,9 +65,10 @@ public final class VirtualAudioController implements AudioPlaybackCallback,
private ArraySet<Integer> mPlayingAppUids = new ArraySet<>();
private GenericWindowPolicyController mGenericWindowPolicyController;
private final Object mCallbackLock = new Object();
- @Nullable
@GuardedBy("mCallbackLock")
- private IAudioSessionCallback mCallback;
+ private IAudioRoutingCallback mRoutingCallback;
+ @GuardedBy("mCallbackLock")
+ private IAudioConfigChangedCallback mConfigChangedCallback;
public VirtualAudioController(Context context) {
mContext = context;
@@ -80,18 +82,22 @@ public final class VirtualAudioController implements AudioPlaybackCallback,
*/
public void startListening(
@NonNull GenericWindowPolicyController genericWindowPolicyController,
- @Nullable IAudioSessionCallback callback) {
+ @NonNull IAudioRoutingCallback routingCallback,
+ @Nullable IAudioConfigChangedCallback configChangedCallback) {
mGenericWindowPolicyController = genericWindowPolicyController;
mGenericWindowPolicyController.setRunningAppsChangedListener(/* listener= */ this);
synchronized (mCallbackLock) {
- mCallback = callback;
+ mRoutingCallback = routingCallback;
+ mConfigChangedCallback = configChangedCallback;
}
synchronized (mLock) {
mRunningAppUids.clear();
mPlayingAppUids.clear();
}
- mAudioPlaybackDetector.register(/* callback= */ this);
- mAudioRecordingDetector.register(/* callback= */ this);
+ if (configChangedCallback != null) {
+ mAudioPlaybackDetector.register(/* callback= */ this);
+ mAudioRecordingDetector.register(/* callback= */ this);
+ }
}
/**
@@ -109,7 +115,8 @@ public final class VirtualAudioController implements AudioPlaybackCallback,
mGenericWindowPolicyController = null;
}
synchronized (mCallbackLock) {
- mCallback = null;
+ mRoutingCallback = null;
+ mConfigChangedCallback = null;
}
}
@@ -169,9 +176,9 @@ public final class VirtualAudioController implements AudioPlaybackCallback,
audioPlaybackConfigurations = findPlaybackConfigurations(configs, mRunningAppUids);
}
synchronized (mCallbackLock) {
- if (mCallback != null) {
+ if (mConfigChangedCallback != null) {
try {
- mCallback.onPlaybackConfigChanged(audioPlaybackConfigurations);
+ mConfigChangedCallback.onPlaybackConfigChanged(audioPlaybackConfigurations);
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException when calling onPlaybackConfigChanged", e);
}
@@ -188,9 +195,9 @@ public final class VirtualAudioController implements AudioPlaybackCallback,
audioRecordingConfigurations = findRecordingConfigurations(configs, mRunningAppUids);
}
synchronized (mCallbackLock) {
- if (mCallback != null) {
+ if (mConfigChangedCallback != null) {
try {
- mCallback.onRecordingConfigChanged(audioRecordingConfigurations);
+ mConfigChangedCallback.onRecordingConfigChanged(audioRecordingConfigurations);
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException when calling onRecordingConfigChanged", e);
}
@@ -227,9 +234,9 @@ public final class VirtualAudioController implements AudioPlaybackCallback,
}
synchronized (mCallbackLock) {
- if (mCallback != null) {
+ if (mRoutingCallback != null) {
try {
- mCallback.onAppsNeedingAudioRoutingChanged(runningUids);
+ mRoutingCallback.onAppsNeedingAudioRoutingChanged(runningUids);
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException when calling updateReroutingApps", e);
}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 68cd28809fd0..f34c5062144e 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -43,6 +43,7 @@ import android.util.ArraySet;
import android.util.SparseArray;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.pm.KnownPackages;
import com.android.server.pm.PackageList;
import com.android.server.pm.PackageSetting;
import com.android.server.pm.dex.DynamicCodeLogger;
@@ -68,51 +69,6 @@ import java.util.function.Consumer;
* @hide Only for use within the system server.
*/
public abstract class PackageManagerInternal {
-
- @IntDef(prefix = "PACKAGE_", value = {
- PACKAGE_SYSTEM,
- PACKAGE_SETUP_WIZARD,
- PACKAGE_INSTALLER,
- PACKAGE_UNINSTALLER,
- PACKAGE_VERIFIER,
- PACKAGE_BROWSER,
- PACKAGE_SYSTEM_TEXT_CLASSIFIER,
- PACKAGE_PERMISSION_CONTROLLER,
- PACKAGE_CONFIGURATOR,
- PACKAGE_INCIDENT_REPORT_APPROVER,
- PACKAGE_APP_PREDICTOR,
- PACKAGE_OVERLAY_CONFIG_SIGNATURE,
- PACKAGE_WIFI,
- PACKAGE_COMPANION,
- PACKAGE_RETAIL_DEMO,
- PACKAGE_RECENTS,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface KnownPackage {}
-
- public static final int PACKAGE_SYSTEM = 0;
- public static final int PACKAGE_SETUP_WIZARD = 1;
- public static final int PACKAGE_INSTALLER = 2;
- public static final int PACKAGE_UNINSTALLER = 3;
- public static final int PACKAGE_VERIFIER = 4;
- public static final int PACKAGE_BROWSER = 5;
- public static final int PACKAGE_SYSTEM_TEXT_CLASSIFIER = 6;
- public static final int PACKAGE_PERMISSION_CONTROLLER = 7;
- public static final int PACKAGE_WELLBEING = 8;
- public static final int PACKAGE_DOCUMENTER = 9;
- public static final int PACKAGE_CONFIGURATOR = 10;
- public static final int PACKAGE_INCIDENT_REPORT_APPROVER = 11;
- public static final int PACKAGE_APP_PREDICTOR = 12;
- public static final int PACKAGE_OVERLAY_CONFIG_SIGNATURE = 13;
- public static final int PACKAGE_WIFI = 14;
- public static final int PACKAGE_COMPANION = 15;
- public static final int PACKAGE_RETAIL_DEMO = 16;
- public static final int PACKAGE_RECENTS = 17;
- public static final int PACKAGE_AMBIENT_CONTEXT_DETECTION = 18;
- // Integer value of the last known package ID. Increases as new ID is added to KnownPackage.
- // Please note the numbers should be continuous.
- public static final int LAST_KNOWN_PACKAGE = PACKAGE_AMBIENT_CONTEXT_DETECTION;
-
@LongDef(flag = true, prefix = "RESOLVE_", value = {
RESOLVE_NON_BROWSER_ONLY,
RESOLVE_NON_RESOLVER_ONLY
@@ -754,12 +710,11 @@ public abstract class PackageManagerInternal {
*/
public abstract boolean isResolveActivityComponent(@NonNull ComponentInfo component);
-
/**
* Returns a list of package names for a known package
*/
public abstract @NonNull String[] getKnownPackageNames(
- @KnownPackage int knownPackage, int userId);
+ @KnownPackages.KnownPackage int knownPackage, int userId);
/**
* Returns whether the package is an instant app.
@@ -1143,55 +1098,6 @@ public abstract class PackageManagerInternal {
@NonNull InstalledLoadingProgressCallback callback, int userId);
/**
- * Returns the string representation of a known package. For example,
- * {@link #PACKAGE_SETUP_WIZARD} is represented by the string Setup Wizard.
- *
- * @param knownPackage The known package.
- * @return The string representation.
- */
- public static @NonNull String knownPackageToString(@KnownPackage int knownPackage) {
- switch (knownPackage) {
- case PACKAGE_SYSTEM:
- return "System";
- case PACKAGE_SETUP_WIZARD:
- return "Setup Wizard";
- case PACKAGE_INSTALLER:
- return "Installer";
- case PACKAGE_UNINSTALLER:
- return "Uninstaller";
- case PACKAGE_VERIFIER:
- return "Verifier";
- case PACKAGE_BROWSER:
- return "Browser";
- case PACKAGE_SYSTEM_TEXT_CLASSIFIER:
- return "System Text Classifier";
- case PACKAGE_PERMISSION_CONTROLLER:
- return "Permission Controller";
- case PACKAGE_WELLBEING:
- return "Wellbeing";
- case PACKAGE_DOCUMENTER:
- return "Documenter";
- case PACKAGE_CONFIGURATOR:
- return "Configurator";
- case PACKAGE_INCIDENT_REPORT_APPROVER:
- return "Incident Report Approver";
- case PACKAGE_APP_PREDICTOR:
- return "App Predictor";
- case PACKAGE_WIFI:
- return "Wi-Fi";
- case PACKAGE_COMPANION:
- return "Companion";
- case PACKAGE_RETAIL_DEMO:
- return "Retail Demo";
- case PACKAGE_OVERLAY_CONFIG_SIGNATURE:
- return "Overlay Config Signature";
- case PACKAGE_RECENTS:
- return "Recents";
- }
- return "Unknown";
- }
-
- /**
* Callback to listen for loading progress of a package installed on Incremental File System.
*/
public abstract static class InstalledLoadingProgressCallback {
diff --git a/services/core/java/com/android/server/AlarmManagerInternal.java b/services/core/java/com/android/server/AlarmManagerInternal.java
index e5ae77a26246..e3c8afabcf6f 100644
--- a/services/core/java/com/android/server/AlarmManagerInternal.java
+++ b/services/core/java/com/android/server/AlarmManagerInternal.java
@@ -44,7 +44,8 @@ public interface AlarmManagerInternal {
/**
* Returns if the given package in the given user holds
- * {@link android.Manifest.permission#SCHEDULE_EXACT_ALARM}
+ * {@link android.Manifest.permission#SCHEDULE_EXACT_ALARM} or
+ * {@link android.Manifest.permission#USE_EXACT_ALARM}.
*/
- boolean hasScheduleExactAlarm(String packageName, int uid);
+ boolean hasExactAlarmPermission(String packageName, int uid);
}
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index 26d76a848a02..aac1035059ec 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -31,7 +31,6 @@ import android.os.RecoverySystem;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
-import android.os.storage.StorageManager;
import android.provider.Downloads;
import android.system.ErrnoException;
import android.system.Os;
@@ -281,14 +280,8 @@ public class BootReceiver extends BroadcastReceiver {
HashMap<String, Long> timestamps = readTimestamps();
if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
- if (StorageManager.inCryptKeeperBounce()) {
- // Encrypted, first boot to get PIN/pattern/password so data is tmpfs
- // Don't set ro.runtime.firstboot so that we will do this again
- // when data is properly mounted
- } else {
- String now = Long.toString(System.currentTimeMillis());
- SystemProperties.set("ro.runtime.firstboot", now);
- }
+ String now = Long.toString(System.currentTimeMillis());
+ SystemProperties.set("ro.runtime.firstboot", now);
if (db != null) db.addText("SYSTEM_BOOT", headers);
// Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile())
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 16ff167380bd..c5eb25b9981e 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -385,6 +385,10 @@ public final class PinnerService extends SystemService {
@Override
public void onUidCachedChanged(int uid, boolean cached) throws RemoteException {
}
+
+ @Override
+ public void onUidProcAdjChanged(int uid) throws RemoteException {
+ }
}, UID_OBSERVER_GONE | UID_OBSERVER_ACTIVE, 0, null);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to register uid observer", e);
diff --git a/services/core/java/com/android/server/SmartStorageMaintIdler.java b/services/core/java/com/android/server/SmartStorageMaintIdler.java
index 2dff72fdc344..899692611086 100644
--- a/services/core/java/com/android/server/SmartStorageMaintIdler.java
+++ b/services/core/java/com/android/server/SmartStorageMaintIdler.java
@@ -46,7 +46,7 @@ public class SmartStorageMaintIdler extends JobService {
}
// ... and try again in a next period
scheduleSmartIdlePass(SmartStorageMaintIdler.this,
- StorageManagerService.SMART_IDLE_MAINT_PERIOD);
+ StorageManagerService.sSmartIdleMaintPeriod);
}
};
@@ -70,7 +70,7 @@ public class SmartStorageMaintIdler extends JobService {
/**
* Schedule the smart storage idle maintenance job
*/
- public static void scheduleSmartIdlePass(Context context, int nHours) {
+ public static void scheduleSmartIdlePass(Context context, int nMinutes) {
StorageManagerService ms = StorageManagerService.sSelf;
if ((ms == null) || ms.isPassedLifetimeThresh()) {
return;
@@ -78,7 +78,7 @@ public class SmartStorageMaintIdler extends JobService {
JobScheduler tm = context.getSystemService(JobScheduler.class);
- long nextScheduleTime = TimeUnit.HOURS.toMillis(nHours);
+ long nextScheduleTime = TimeUnit.MINUTES.toMillis(nMinutes);
JobInfo.Builder builder = new JobInfo.Builder(SMART_MAINT_JOB_ID,
SMART_STORAGE_MAINT_SERVICE);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index af7dcd114066..e6bf109ff84c 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -128,6 +128,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.DataUnit;
+import android.util.EventLog;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -336,13 +337,15 @@ class StorageManagerService extends IStorageManager.Stub
@Nullable public static String sMediaStoreAuthorityProcessName;
- // Run period in hour for smart idle maintenance
- static final int SMART_IDLE_MAINT_PERIOD = 1;
+ // Smart idle maintenance running period in minute
+ static volatile int sSmartIdleMaintPeriod = 60;
private final AtomicFile mSettingsFile;
- private final AtomicFile mHourlyWriteFile;
+ private final AtomicFile mWriteRecordFile;
- private static final int MAX_HOURLY_WRITE_RECORDS = 72;
+ // 72 hours (3 days)
+ private static final int MAX_PERIOD_WRITE_RECORD = 72 * 60;
+ private volatile int mMaxWriteRecords;
/**
* Default config values for smart idle maintenance
@@ -350,6 +353,10 @@ class StorageManagerService extends IStorageManager.Stub
*/
// Decide whether smart idle maintenance is enabled or not
private static final boolean DEFAULT_SMART_IDLE_MAINT_ENABLED = false;
+ // Run period in minute for smart idle maintenance
+ private static final int DEFAULT_SMART_IDLE_MAINT_PERIOD = 60;
+ private static final int MIN_SMART_IDLE_MAINT_PERIOD = 10;
+ private static final int MAX_SMART_IDLE_MAINT_PERIOD = 24 * 60;
// Storage lifetime percentage threshold to decide to turn off the feature
private static final int DEFAULT_LIFETIME_PERCENT_THRESHOLD = 70;
// Minimum required number of dirty + free segments to trigger GC
@@ -372,8 +379,8 @@ class StorageManagerService extends IStorageManager.Stub
private volatile boolean mNeedGC;
private volatile boolean mPassedLifetimeThresh;
- // Tracking storage hourly write amounts
- private volatile int[] mStorageHourlyWrites;
+ // Tracking storage write amounts in one period
+ private volatile int[] mStorageWriteRecords;
/**
* <em>Never</em> hold the lock while performing downcalls into vold, since
@@ -929,7 +936,7 @@ class StorageManagerService extends IStorageManager.Stub
private void handleSystemReady() {
if (prepareSmartIdleMaint()) {
- SmartStorageMaintIdler.scheduleSmartIdlePass(mContext, SMART_IDLE_MAINT_PERIOD);
+ SmartStorageMaintIdler.scheduleSmartIdlePass(mContext, sSmartIdleMaintPeriod);
}
// Start scheduling nominally-daily fstrim operations
@@ -1950,10 +1957,19 @@ class StorageManagerService extends IStorageManager.Stub
mSettingsFile = new AtomicFile(
new File(Environment.getDataSystemDirectory(), "storage.xml"), "storage-settings");
- mHourlyWriteFile = new AtomicFile(
- new File(Environment.getDataSystemDirectory(), "storage-hourly-writes"));
+ mWriteRecordFile = new AtomicFile(
+ new File(Environment.getDataSystemDirectory(), "storage-write-records"));
- mStorageHourlyWrites = new int[MAX_HOURLY_WRITE_RECORDS];
+ sSmartIdleMaintPeriod = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "smart_idle_maint_period", DEFAULT_SMART_IDLE_MAINT_PERIOD);
+ if (sSmartIdleMaintPeriod < MIN_SMART_IDLE_MAINT_PERIOD) {
+ sSmartIdleMaintPeriod = MIN_SMART_IDLE_MAINT_PERIOD;
+ } else if (sSmartIdleMaintPeriod > MAX_SMART_IDLE_MAINT_PERIOD) {
+ sSmartIdleMaintPeriod = MAX_SMART_IDLE_MAINT_PERIOD;
+ }
+
+ mMaxWriteRecords = MAX_PERIOD_WRITE_RECORD / sSmartIdleMaintPeriod;
+ mStorageWriteRecords = new int[mMaxWriteRecords];
synchronized (mLock) {
readSettingsLocked();
@@ -2696,7 +2712,7 @@ class StorageManagerService extends IStorageManager.Stub
// maintenance to avoid the conflict
mNeedGC = false;
- loadStorageHourlyWrites();
+ loadStorageWriteRecords();
try {
mVold.refreshLatestWrite();
} catch (Exception e) {
@@ -2712,13 +2728,17 @@ class StorageManagerService extends IStorageManager.Stub
return mPassedLifetimeThresh;
}
- private void loadStorageHourlyWrites() {
+ private void loadStorageWriteRecords() {
FileInputStream fis = null;
try {
- fis = mHourlyWriteFile.openRead();
+ fis = mWriteRecordFile.openRead();
ObjectInputStream ois = new ObjectInputStream(fis);
- mStorageHourlyWrites = (int[])ois.readObject();
+
+ int periodValue = ois.readInt();
+ if (periodValue == sSmartIdleMaintPeriod) {
+ mStorageWriteRecords = (int[]) ois.readObject();
+ }
} catch (FileNotFoundException e) {
// Missing data is okay, probably first boot
} catch (Exception e) {
@@ -2728,24 +2748,26 @@ class StorageManagerService extends IStorageManager.Stub
}
}
- private int getAverageHourlyWrite() {
- return Arrays.stream(mStorageHourlyWrites).sum() / MAX_HOURLY_WRITE_RECORDS;
+ private int getAverageWriteAmount() {
+ return Arrays.stream(mStorageWriteRecords).sum() / mMaxWriteRecords;
}
- private void updateStorageHourlyWrites(int latestWrite) {
+ private void updateStorageWriteRecords(int latestWrite) {
FileOutputStream fos = null;
- System.arraycopy(mStorageHourlyWrites,0, mStorageHourlyWrites, 1,
- MAX_HOURLY_WRITE_RECORDS - 1);
- mStorageHourlyWrites[0] = latestWrite;
+ System.arraycopy(mStorageWriteRecords, 0, mStorageWriteRecords, 1,
+ mMaxWriteRecords - 1);
+ mStorageWriteRecords[0] = latestWrite;
try {
- fos = mHourlyWriteFile.startWrite();
+ fos = mWriteRecordFile.startWrite();
ObjectOutputStream oos = new ObjectOutputStream(fos);
- oos.writeObject(mStorageHourlyWrites);
- mHourlyWriteFile.finishWrite(fos);
+
+ oos.writeInt(sSmartIdleMaintPeriod);
+ oos.writeObject(mStorageWriteRecords);
+ mWriteRecordFile.finishWrite(fos);
} catch (IOException e) {
if (fos != null) {
- mHourlyWriteFile.failWrite(fos);
+ mWriteRecordFile.failWrite(fos);
}
}
}
@@ -2809,22 +2831,23 @@ class StorageManagerService extends IStorageManager.Stub
return;
}
- int latestHourlyWrite = mVold.getWriteAmount();
- if (latestHourlyWrite == -1) {
- Slog.w(TAG, "Failed to get storage hourly write");
+ int latestWrite = mVold.getWriteAmount();
+ if (latestWrite == -1) {
+ Slog.w(TAG, "Failed to get storage write record");
return;
}
- updateStorageHourlyWrites(latestHourlyWrite);
- int avgHourlyWrite = getAverageHourlyWrite();
+ updateStorageWriteRecords(latestWrite);
+ int avgWriteAmount = getAverageWriteAmount();
- Slog.i(TAG, "Set smart idle maintenance: " + "latest hourly write: " +
- latestHourlyWrite + ", average hourly write: " + avgHourlyWrite +
+ Slog.i(TAG, "Set smart idle maintenance: " + "latest write amount: " +
+ latestWrite + ", average write amount: " + avgWriteAmount +
", min segment threshold: " + mMinSegmentsThreshold +
", dirty reclaim rate: " + mDirtyReclaimRate +
- ", segment reclaim weight:" + mSegmentReclaimWeight);
- mVold.setGCUrgentPace(avgHourlyWrite, mMinSegmentsThreshold, mDirtyReclaimRate,
- mSegmentReclaimWeight);
+ ", segment reclaim weight: " + mSegmentReclaimWeight +
+ ", period: " + sSmartIdleMaintPeriod);
+ mVold.setGCUrgentPace(avgWriteAmount, mMinSegmentsThreshold, mDirtyReclaimRate,
+ mSegmentReclaimWeight, sSmartIdleMaintPeriod);
} else {
Slog.i(TAG, "Skipping smart idle maintenance - block based checkpoint in progress");
}
@@ -3376,6 +3399,7 @@ class StorageManagerService extends IStorageManager.Stub
}
}
} catch (Exception e) {
+ EventLog.writeEvent(0x534e4554, "224585613", -1, "");
Slog.wtf(TAG, e);
// Make sure to re-throw this exception; we must not ignore failure
// to prepare the user storage as it could indicate that encryption
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 2c0514d7d0aa..730907c7d049 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1875,7 +1875,7 @@ public final class ActiveServices {
if (delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs) {
resetFgsRestrictionLocked(r);
setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
- r.appInfo.uid, r.intent.getIntent(), r, r.userId,false);
+ r.appInfo.uid, r.intent.getIntent(), r, r.userId, false);
final String temp = "startForegroundDelayMs:" + delayMs;
if (r.mInfoAllowStartForeground != null) {
r.mInfoAllowStartForeground += "; " + temp;
@@ -1888,12 +1888,8 @@ public final class ActiveServices {
} else if (r.mStartForegroundCount >= 1) {
// The second or later time startForeground() is called after service is
// started. Check for app state again.
- final long delayMs = SystemClock.elapsedRealtime() -
- r.mLastSetFgsRestrictionTime;
- if (delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs) {
- setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
- r.appInfo.uid, r.intent.getIntent(), r, r.userId,false);
- }
+ setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
+ r.appInfo.uid, r.intent.getIntent(), r, r.userId, false);
}
// If the foreground service is not started from TOP process, do not allow it to
// have while-in-use location/camera/microphone access.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 450cfbbace75..be0d79776069 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -15302,7 +15302,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if ((enqueuedChange & UidRecord.CHANGE_GONE) != 0) {
mLocalPowerManager.uidGone(uid);
- } else {
+ } else if ((enqueuedChange & UidRecord.CHANGE_PROCSTATE) != 0) {
mLocalPowerManager.updateUidProcState(uid, procState);
}
}
@@ -15573,7 +15573,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@GuardedBy("this")
final void doStopUidLocked(int uid, final UidRecord uidRec) {
mServices.stopInBackgroundLocked(uid);
- enqueueUidChangeLocked(uidRec, uid, UidRecord.CHANGE_IDLE);
+ enqueueUidChangeLocked(uidRec, uid, UidRecord.CHANGE_IDLE | UidRecord.CHANGE_PROCSTATE);
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 5024a4a1cba0..71ae92aecbcf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -1680,6 +1680,10 @@ final class ActivityManagerShellCommand extends ShellCommand {
}
@Override
+ public void onUidProcAdjChanged(int uid) throws RemoteException {
+ }
+
+ @Override
public void onOomAdjMessage(String msg) {
synchronized (this) {
final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index 690051f47326..0cbc7ad404f5 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -20,6 +20,7 @@ import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
import static android.app.ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED;
import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET;
+import static android.app.ActivityManager.RESTRICTION_LEVEL_UNKNOWN;
import static android.app.ActivityManager.isLowRamDeviceStatic;
import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM;
import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
@@ -1119,6 +1120,13 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_high_threshold_by_bg_location";
/**
+ * Whether or not the battery usage of the offending app should fulfill the 1st threshold
+ * before taking actions for the 2nd threshold.
+ */
+ static final String KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS =
+ DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_decouple_thresholds";
+
+ /**
* Default value to the {@link #INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD} of
* the {@link #mBgCurrentDrainRestrictedBucketThreshold}.
*/
@@ -1191,6 +1199,11 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
final boolean mDefaultBgCurrentDrainHighThresholdByBgLocation;
/**
+ * Default value to {@link #mBgCurrentDrainDecoupleThresholds}.
+ */
+ static final boolean DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD = true;
+
+ /**
* The index to {@link #mBgCurrentDrainRestrictedBucketThreshold}
* and {@link #mBgCurrentDrainBgRestrictedThreshold}.
*/
@@ -1258,6 +1271,11 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
volatile boolean mBgCurrentDrainHighThresholdByBgLocation;
/**
+ * @see #KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS.
+ */
+ volatile boolean mBgCurrentDrainDecoupleThresholds;
+
+ /**
* The capacity of the battery when fully charged in mAh.
*/
private int mBatteryFullChargeMah;
@@ -1369,6 +1387,9 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
case KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES:
updateCurrentDrainExemptedTypes();
break;
+ case KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS:
+ updateCurrentDrainDecoupleThresholds();
+ break;
default:
super.onPropertiesChanged(name);
break;
@@ -1466,6 +1487,13 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
mDefaultBgCurrentDrainExemptedTypes);
}
+ private void updateCurrentDrainDecoupleThresholds() {
+ mBgCurrentDrainDecoupleThresholds = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS,
+ DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD);
+ }
+
@Override
public void onSystemReady() {
mBatteryFullChargeMah =
@@ -1477,20 +1505,30 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
updateCurrentDrainLocationMinDuration();
updateCurrentDrainEventDurationBasedThresholdEnabled();
updateCurrentDrainExemptedTypes();
+ updateCurrentDrainDecoupleThresholds();
}
@Override
- public @RestrictionLevel int getProposedRestrictionLevel(String packageName, int uid) {
+ @RestrictionLevel
+ public int getProposedRestrictionLevel(String packageName, int uid,
+ @RestrictionLevel int maxLevel) {
+ if (maxLevel <= RESTRICTION_LEVEL_ADAPTIVE_BUCKET) {
+ return RESTRICTION_LEVEL_UNKNOWN;
+ }
synchronized (mLock) {
- final int index = mHighBgBatteryPackages.indexOfKey(uid);
- if (index < 0) {
- // Not found, return adaptive as the default one.
- return RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
+ final long[] ts = mHighBgBatteryPackages.get(uid);
+ if (ts != null) {
+ final int restrictedLevel = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] > 0
+ ? RESTRICTION_LEVEL_RESTRICTED_BUCKET
+ : RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
+ if (maxLevel > RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) {
+ return ts[TIME_STAMP_INDEX_BG_RESTRICTED] > 0
+ ? RESTRICTION_LEVEL_BACKGROUND_RESTRICTED : restrictedLevel;
+ } else if (maxLevel == RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) {
+ return restrictedLevel;
+ }
}
- final long[] ts = mHighBgBatteryPackages.valueAt(index);
- return ts[TIME_STAMP_INDEX_BG_RESTRICTED] > 0
- ? RESTRICTION_LEVEL_BACKGROUND_RESTRICTED
- : RESTRICTION_LEVEL_RESTRICTED_BUCKET;
+ return RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
}
}
@@ -1573,36 +1611,58 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
final int thresholdIndex = getCurrentDrainThresholdIndex(uid, now,
mBgCurrentDrainWindowMs);
final int index = mHighBgBatteryPackages.indexOfKey(uid);
+ final boolean decoupleThresholds = mBgCurrentDrainDecoupleThresholds;
+ final double rbThreshold = mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex];
+ final double brThreshold = mBgCurrentDrainBgRestrictedThreshold[thresholdIndex];
if (index < 0) {
- if (rbPercentage >= mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex]) {
+ long[] ts = null;
+ if (rbPercentage >= rbThreshold) {
// New findings to us, track it and let the controller know.
- final long[] ts = new long[TIME_STAMP_INDEX_LAST];
+ ts = new long[TIME_STAMP_INDEX_LAST];
ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now;
mHighBgBatteryPackages.put(uid, ts);
notifyController = excessive = true;
}
+ if (decoupleThresholds && brPercentage >= brThreshold) {
+ if (ts == null) {
+ ts = new long[TIME_STAMP_INDEX_LAST];
+ mHighBgBatteryPackages.put(uid, ts);
+ }
+ ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now;
+ notifyController = excessive = true;
+ }
} else {
final long[] ts = mHighBgBatteryPackages.valueAt(index);
- if (rbPercentage < mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex]) {
- // it's actually back to normal, but we don't untrack it until
- // explicit user interactions.
- notifyController = true;
+ final long lastRestrictBucketTs = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET];
+ if (rbPercentage >= rbThreshold) {
+ if (lastRestrictBucketTs == 0) {
+ ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now;
+ }
+ notifyController = excessive = true;
} else {
- excessive = true;
- if (brPercentage >= mBgCurrentDrainBgRestrictedThreshold[thresholdIndex]
- && curLevel == RESTRICTION_LEVEL_RESTRICTED_BUCKET) {
- // If we're in the restricted standby bucket but still seeing high
- // current drains, tell the controller again.
- final long lastResbucket = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET];
- final long lastBgRes = ts[TIME_STAMP_INDEX_BG_RESTRICTED];
- // If it has been a while since restricting the app and since the last
- // time we notify the controller, notify it again.
- if ((now >= lastResbucket + mBgCurrentDrainWindowMs) && (lastBgRes == 0
- || (now >= lastBgRes + mBgCurrentDrainWindowMs))) {
- ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now;
- notifyController = true;
- }
+ // It's actually back to normal, but we don't untrack it until
+ // explicit user interactions, because the restriction could be the cause
+ // of going back to normal.
+ }
+ if (brPercentage >= brThreshold) {
+ // If either
+ // a) It's configured to goto threshold 2 directly without threshold 1;
+ // b) It's already in the restricted standby bucket, but still seeing
+ // high current drains, and it's been a while since it's restricted;
+ // tell the controller.
+ notifyController = decoupleThresholds
+ || (curLevel == RESTRICTION_LEVEL_RESTRICTED_BUCKET
+ && (now > lastRestrictBucketTs + mBgCurrentDrainWindowMs));
+ if (notifyController) {
+ ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now;
}
+ excessive = true;
+ } else {
+ // Reset the track now - if it's already background restricted, it requires
+ // user consent to unrestrict it; or if it's in restricted bucket level,
+ // resetting this won't lift it from that level.
+ ts[TIME_STAMP_INDEX_BG_RESTRICTED] = 0;
+ // Now need to notify the controller.
}
}
}
diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java
index b8fb9e85ac08..de94929fbafc 100644
--- a/services/core/java/com/android/server/am/AppRestrictionController.java
+++ b/services/core/java/com/android/server/am/AppRestrictionController.java
@@ -24,6 +24,7 @@ import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
import static android.app.ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED;
import static android.app.ActivityManager.RESTRICTION_LEVEL_EXEMPTED;
import static android.app.ActivityManager.RESTRICTION_LEVEL_HIBERNATION;
+import static android.app.ActivityManager.RESTRICTION_LEVEL_MAX;
import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET;
import static android.app.ActivityManager.RESTRICTION_LEVEL_UNKNOWN;
import static android.app.ActivityManager.UID_OBSERVER_ACTIVE;
@@ -185,6 +186,12 @@ public final class AppRestrictionController {
*/
private static final boolean ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER = true;
+ /**
+ * Whether or not to show the action to the foreground service manager when
+ * posting the notification for background restriction.
+ */
+ private static final boolean ENABLE_SHOW_FGS_MANAGER_ACTION_ON_BG_RESTRICTION = false;
+
private final Context mContext;
private final HandlerThread mBgHandlerThread;
private final BgHandler mBgHandler;
@@ -665,6 +672,14 @@ public final class AppRestrictionController {
DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "prompt_fgs_with_noti_to_bg_restricted";
/**
+ * The behavior for an app with a FGS and its notification is still showing, when the system
+ * detects it's running for a very long time, should we prompt the user.
+ * {@code true} - we'll show the prompt to user, {@code false} - we'll not show it.
+ */
+ static final String KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING =
+ DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "prompt_fgs_with_noti_on_long_running";
+
+ /**
* The list of packages to be exempted from all these background restrictions.
*/
static final String KEY_BG_RESTRICTION_EXEMPTED_PACKAGES =
@@ -678,7 +693,7 @@ public final class AppRestrictionController {
/**
* Default value to {@link #mBgAbusiveNotificationMinIntervalMs}.
*/
- static final long DEFAULT_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL_MS = ONE_DAY;
+ static final long DEFAULT_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL_MS = 30 * ONE_DAY;
/**
* Default value to {@link #mBgAbusiveNotificationMinIntervalMs}.
@@ -686,6 +701,11 @@ public final class AppRestrictionController {
static final long DEFAULT_BG_LONG_FGS_NOTIFICATION_MINIMAL_INTERVAL_MS = 30 * ONE_DAY;
/**
+ * Default value to {@link #mBgPromptFgsWithNotiOnLongRunning}.
+ */
+ static final boolean DEFAULT_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING = false;
+
+ /**
* Default value to {@link #mBgPromptFgsWithNotiToBgRestricted}.
*/
final boolean mDefaultBgPromptFgsWithNotiToBgRestricted;
@@ -710,6 +730,11 @@ public final class AppRestrictionController {
*/
volatile boolean mBgPromptFgsWithNotiToBgRestricted;
+ /**
+ * @see #KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING.
+ */
+ volatile boolean mBgPromptFgsWithNotiOnLongRunning;
+
ConstantsObserver(Handler handler, Context context) {
super(handler);
mDefaultBgPromptFgsWithNotiToBgRestricted = context.getResources().getBoolean(
@@ -735,6 +760,9 @@ public final class AppRestrictionController {
case KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_TO_BG_RESTRICTED:
updateBgPromptFgsWithNotiToBgRestricted();
break;
+ case KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING:
+ updateBgPromptFgsWithNotiOnLongRunning();
+ break;
case KEY_BG_RESTRICTION_EXEMPTED_PACKAGES:
updateBgRestrictionExemptedPackages();
break;
@@ -771,6 +799,7 @@ public final class AppRestrictionController {
updateBgAbusiveNotificationMinimalInterval();
updateBgLongFgsNotificationMinimalInterval();
updateBgPromptFgsWithNotiToBgRestricted();
+ updateBgPromptFgsWithNotiOnLongRunning();
updateBgRestrictionExemptedPackages();
}
@@ -806,6 +835,13 @@ public final class AppRestrictionController {
mDefaultBgPromptFgsWithNotiToBgRestricted);
}
+ private void updateBgPromptFgsWithNotiOnLongRunning() {
+ mBgPromptFgsWithNotiOnLongRunning = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING,
+ DEFAULT_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING);
+ }
+
private void updateBgRestrictionExemptedPackages() {
final String settings = DeviceConfig.getString(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -908,6 +944,10 @@ public final class AppRestrictionController {
@Override
public void onUidCachedChanged(int uid, boolean cached) {
}
+
+ @Override
+ public void onUidProcAdjChanged(int uid) {
+ }
};
/**
@@ -1148,7 +1188,8 @@ public final class AppRestrictionController {
? RESTRICTION_LEVEL_RESTRICTED_BUCKET
: RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
if (calcTrackers) {
- @RestrictionLevel int l = calcAppRestrictionLevelFromTackers(uid, packageName);
+ @RestrictionLevel int l = calcAppRestrictionLevelFromTackers(uid, packageName,
+ RESTRICTION_LEVEL_MAX);
if (l == RESTRICTION_LEVEL_EXEMPTED) {
return RESTRICTION_LEVEL_EXEMPTED;
}
@@ -1160,7 +1201,8 @@ public final class AppRestrictionController {
uid, 0, packageName).sendToTarget();
}
// Lower the level.
- level = RESTRICTION_LEVEL_RESTRICTED_BUCKET;
+ level = calcAppRestrictionLevelFromTackers(uid, packageName,
+ RESTRICTION_LEVEL_BACKGROUND_RESTRICTED);
}
}
break;
@@ -1177,12 +1219,13 @@ public final class AppRestrictionController {
* monitors certain dimensions of the app, the abusive behaviors could be detected in one or
* more of these dimensions, but not necessarily all of them. </p>
*/
- private @RestrictionLevel int calcAppRestrictionLevelFromTackers(int uid, String packageName) {
+ private @RestrictionLevel int calcAppRestrictionLevelFromTackers(int uid, String packageName,
+ @RestrictionLevel int maxLevel) {
@RestrictionLevel int level = RESTRICTION_LEVEL_UNKNOWN;
final boolean isRestrictedBucketEnabled = mConstantsObserver.mRestrictedBucketEnabled;
for (int i = mAppStateTrackers.size() - 1; i >= 0; i--) {
@RestrictionLevel int l = mAppStateTrackers.get(i).getPolicy()
- .getProposedRestrictionLevel(packageName, uid);
+ .getProposedRestrictionLevel(packageName, uid, maxLevel);
if (!isRestrictedBucketEnabled && l == RESTRICTION_LEVEL_RESTRICTED_BUCKET) {
l = RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
}
@@ -1471,17 +1514,15 @@ public final class AppRestrictionController {
} else if (curLevel >= RESTRICTION_LEVEL_RESTRICTED_BUCKET
&& level < RESTRICTION_LEVEL_RESTRICTED_BUCKET) {
// Moved out of the background-restricted state.
- if (curBucket != STANDBY_BUCKET_RARE) {
- synchronized (mSettingsLock) {
- final int index = mActiveUids.indexOfKey(uid, pkgName);
- if (index >= 0) {
- mActiveUids.add(uid, pkgName, null);
- }
+ synchronized (mSettingsLock) {
+ final int index = mActiveUids.indexOfKey(uid, pkgName);
+ if (index >= 0) {
+ mActiveUids.add(uid, pkgName, null);
}
- appStandbyInternal.maybeUnrestrictApp(pkgName, UserHandle.getUserId(uid),
- prevReason & REASON_MAIN_MASK, prevReason & REASON_SUB_MASK,
- reason, subReason);
}
+ appStandbyInternal.maybeUnrestrictApp(pkgName, UserHandle.getUserId(uid),
+ prevReason & REASON_MAIN_MASK, prevReason & REASON_SUB_MASK,
+ reason, subReason);
}
}
@@ -1685,7 +1726,9 @@ public final class AppRestrictionController {
return;
}
}
- if (ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER && hasForegroundServices) {
+ if (ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER
+ && ENABLE_SHOW_FGS_MANAGER_ACTION_ON_BG_RESTRICTION
+ && hasForegroundServices) {
final Intent trampoline = new Intent(ACTION_FGS_MANAGER_TRAMPOLINE);
trampoline.setPackage("android");
trampoline.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
@@ -1710,6 +1753,13 @@ public final class AppRestrictionController {
void postLongRunningFgsIfNecessary(String packageName, int uid) {
PendingIntent pendingIntent;
+ if (!mBgController.mConstantsObserver.mBgPromptFgsWithNotiOnLongRunning
+ && mBgController.hasForegroundServiceNotifications(packageName, uid)) {
+ if (DEBUG_BG_RESTRICTION_CONTROLLER) {
+ Slog.i(TAG, "Not prompt long-running due to FGS with notification");
+ }
+ return;
+ }
if (ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER) {
final Intent intent = new Intent(ACTION_SHOW_FOREGROUND_SERVICE_MANAGER);
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
@@ -1726,7 +1776,7 @@ public final class AppRestrictionController {
}
postNotificationIfNecessary(NOTIFICATION_TYPE_LONG_RUNNING_FGS,
- com.android.internal.R.string.notification_title_abusive_bg_apps,
+ com.android.internal.R.string.notification_title_long_running_fgs,
com.android.internal.R.string.notification_content_long_running_fgs,
pendingIntent, packageName, uid, null);
}
diff --git a/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
index 262e79521e8c..9b5f18caf71a 100644
--- a/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
+++ b/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
@@ -57,9 +57,6 @@ final class AppWaitingForDebuggerDialog extends BaseErrorDialog {
attrs.setTitle("Waiting For Debugger: " + app.info.processName);
getWindow().setAttributes(attrs);
}
-
- public void onStop() {
- }
@Override
protected void closeDialog() {
diff --git a/services/core/java/com/android/server/am/BaseAppStatePolicy.java b/services/core/java/com/android/server/am/BaseAppStatePolicy.java
index 67318a763907..a55344caea9a 100644
--- a/services/core/java/com/android/server/am/BaseAppStatePolicy.java
+++ b/services/core/java/com/android/server/am/BaseAppStatePolicy.java
@@ -87,9 +87,11 @@ public abstract class BaseAppStatePolicy<T extends BaseAppStateTracker> {
}
/**
- * @return The proposed background restriction policy for the given package/uid.
+ * @return The proposed background restriction policy for the given package/uid,
+ * the returned level should be capped at {@code maxLevel} (exclusive).
*/
- public @RestrictionLevel int getProposedRestrictionLevel(String packageName, int uid) {
+ public @RestrictionLevel int getProposedRestrictionLevel(String packageName, int uid,
+ @RestrictionLevel int maxLevel) {
return RESTRICTION_LEVEL_UNKNOWN;
}
diff --git a/services/core/java/com/android/server/am/BaseAppStateTimeSlotEventsTracker.java b/services/core/java/com/android/server/am/BaseAppStateTimeSlotEventsTracker.java
index 2fbca1fa1724..b8aee13ccdd7 100644
--- a/services/core/java/com/android/server/am/BaseAppStateTimeSlotEventsTracker.java
+++ b/services/core/java/com/android/server/am/BaseAppStateTimeSlotEventsTracker.java
@@ -18,6 +18,7 @@ package com.android.server.am;
import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET;
+import static android.app.ActivityManager.RESTRICTION_LEVEL_UNKNOWN;
import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM;
import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE;
@@ -295,11 +296,19 @@ abstract class BaseAppStateTimeSlotEventsTracker
}
@Override
- public @RestrictionLevel int getProposedRestrictionLevel(String packageName, int uid) {
+ @RestrictionLevel
+ public int getProposedRestrictionLevel(String packageName, int uid,
+ @RestrictionLevel int maxLevel) {
synchronized (mLock) {
- return mExcessiveEventPkgs.get(packageName, uid) == null
+ final int level = mExcessiveEventPkgs.get(packageName, uid) == null
? RESTRICTION_LEVEL_ADAPTIVE_BUCKET
: RESTRICTION_LEVEL_RESTRICTED_BUCKET;
+ if (maxLevel > RESTRICTION_LEVEL_RESTRICTED_BUCKET) {
+ return level;
+ } else if (maxLevel == RESTRICTION_LEVEL_RESTRICTED_BUCKET) {
+ return RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
+ }
+ return RESTRICTION_LEVEL_UNKNOWN;
}
}
diff --git a/services/core/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java
index 259dd8ec567d..b1cfd7fa0f58 100644
--- a/services/core/java/com/android/server/am/BaseErrorDialog.java
+++ b/services/core/java/com/android/server/am/BaseErrorDialog.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import static android.content.Context.RECEIVER_EXPORTED;
+
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -34,6 +36,7 @@ public class BaseErrorDialog extends AlertDialog {
private static final int DISABLE_BUTTONS = 1;
private boolean mConsuming = true;
+ private BroadcastReceiver mReceiver;
public BaseErrorDialog(Context context) {
super(context, com.android.internal.R.style.Theme_DeviceDefault_Dialog_AppError);
@@ -52,14 +55,33 @@ public class BaseErrorDialog extends AlertDialog {
super.onStart();
mHandler.sendEmptyMessage(DISABLE_BUTTONS);
mHandler.sendMessageDelayed(mHandler.obtainMessage(ENABLE_BUTTONS), 1000);
- getContext().registerReceiver(mReceiver,
- new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), Context.RECEIVER_EXPORTED);
+ if (mReceiver == null) {
+ mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+ closeDialog();
+ }
+ }
+ };
+ getContext().registerReceiver(mReceiver,
+ new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), RECEIVER_EXPORTED);
+ }
}
@Override
protected void onStop() {
super.onStop();
- getContext().unregisterReceiver(mReceiver);
+ if (mReceiver != null) {
+ try {
+ getContext().unregisterReceiver(mReceiver);
+ } catch (IllegalArgumentException e) {
+ // Receiver not registered exception.
+ android.util.Slog.e("BaseErrorDialog",
+ "unregisterReceiver threw exception: " + e.getMessage());
+ }
+ mReceiver = null;
+ }
}
public boolean dispatchKeyEvent(KeyEvent event) {
@@ -107,13 +129,4 @@ public class BaseErrorDialog extends AlertDialog {
dismiss();
}
}
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
- closeDialog();
- }
- }
- };
}
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 4fdc88d3fd64..84969aa9e916 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -565,11 +565,24 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
new SynchronousResultReceiver("bluetooth");
adapter.requestControllerActivityEnergyInfo(
Runnable::run,
- info -> {
- Bundle bundle = new Bundle();
- bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY,
- info);
- resultReceiver.send(0, bundle);
+ new BluetoothAdapter.OnBluetoothActivityEnergyInfoCallback() {
+ @Override
+ public void onBluetoothActivityEnergyInfoAvailable(
+ BluetoothActivityEnergyInfo info) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(
+ BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, info);
+ resultReceiver.send(0, bundle);
+ }
+
+ @Override
+ public void onBluetoothActivityEnergyInfoError(int errorCode) {
+ Slog.w(TAG, "error reading Bluetooth stats: " + errorCode);
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(
+ BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, null);
+ resultReceiver.send(0, bundle);
+ }
}
);
bluetoothReceiver = resultReceiver;
diff --git a/services/core/java/com/android/server/am/DataConnectionStats.java b/services/core/java/com/android/server/am/DataConnectionStats.java
index 4c96078bea36..f0910dcb0da2 100644
--- a/services/core/java/com/android/server/am/DataConnectionStats.java
+++ b/services/core/java/com/android/server/am/DataConnectionStats.java
@@ -73,8 +73,7 @@ public class DataConnectionStats extends BroadcastReceiver {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
- mContext.registerReceiver(this, filter, null /* broadcastPermission */, mListenerHandler,
- Context.RECEIVER_NOT_EXPORTED);
+ mContext.registerReceiver(this, filter, null /* broadcastPermission */, mListenerHandler);
}
@Override
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 02206ffc7bef..4ecc36d2750c 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1191,67 +1191,88 @@ public class OomAdjuster {
}
for (int i = activeUids.size() - 1; i >= 0; i--) {
final UidRecord uidRec = activeUids.valueAt(i);
- int uidChange = UidRecord.CHANGE_PROCSTATE;
- if (uidRec.getCurProcState() != PROCESS_STATE_NONEXISTENT
- && (uidRec.getSetProcState() != uidRec.getCurProcState()
- || uidRec.getSetCapability() != uidRec.getCurCapability()
- || uidRec.isSetAllowListed() != uidRec.isCurAllowListed())) {
- if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "Changes in " + uidRec
- + ": proc state from " + uidRec.getSetProcState() + " to "
- + uidRec.getCurProcState() + ", capability from "
- + uidRec.getSetCapability() + " to " + uidRec.getCurCapability()
- + ", allowlist from " + uidRec.isSetAllowListed()
- + " to " + uidRec.isCurAllowListed());
- if (ActivityManager.isProcStateBackground(uidRec.getCurProcState())
- && !uidRec.isCurAllowListed()) {
- // UID is now in the background (and not on the temp allowlist). Was it
- // previously in the foreground (or on the temp allowlist)?
- if (!ActivityManager.isProcStateBackground(uidRec.getSetProcState())
- || uidRec.isSetAllowListed()) {
- uidRec.setLastBackgroundTime(nowElapsed);
- if (!mService.mHandler.hasMessages(IDLE_UIDS_MSG)) {
- // Note: the background settle time is in elapsed realtime, while
- // the handler time base is uptime. All this means is that we may
- // stop background uids later than we had intended, but that only
- // happens because the device was sleeping so we are okay anyway.
- mService.mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
- mConstants.BACKGROUND_SETTLE_TIME);
+ if (uidRec.getCurProcState() != PROCESS_STATE_NONEXISTENT) {
+ if (uidRec.getSetProcState() != uidRec.getCurProcState()
+ || uidRec.getSetCapability() != uidRec.getCurCapability()
+ || uidRec.isSetAllowListed() != uidRec.isCurAllowListed()
+ || uidRec.getProcAdjChanged()) {
+ int uidChange = 0;
+ if (DEBUG_UID_OBSERVERS) {
+ Slog.i(TAG_UID_OBSERVERS, "Changes in " + uidRec
+ + ": proc state from " + uidRec.getSetProcState() + " to "
+ + uidRec.getCurProcState() + ", capability from "
+ + uidRec.getSetCapability() + " to " + uidRec.getCurCapability()
+ + ", allowlist from " + uidRec.isSetAllowListed()
+ + " to " + uidRec.isCurAllowListed()
+ + ", procAdjChanged: " + uidRec.getProcAdjChanged());
+ }
+ if (ActivityManager.isProcStateBackground(uidRec.getCurProcState())
+ && !uidRec.isCurAllowListed()) {
+ // UID is now in the background (and not on the temp allowlist). Was it
+ // previously in the foreground (or on the temp allowlist)?
+ if (!ActivityManager.isProcStateBackground(uidRec.getSetProcState())
+ || uidRec.isSetAllowListed()) {
+ uidRec.setLastBackgroundTime(nowElapsed);
+ if (!mService.mHandler.hasMessages(IDLE_UIDS_MSG)) {
+ // Note: the background settle time is in elapsed realtime, while
+ // the handler time base is uptime. All this means is that we may
+ // stop background uids later than we had intended, but that only
+ // happens because the device was sleeping so we are okay anyway.
+ mService.mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
+ mConstants.BACKGROUND_SETTLE_TIME);
+ }
+ }
+ if (uidRec.isIdle() && !uidRec.isSetIdle()) {
+ uidChange |= UidRecord.CHANGE_IDLE;
+ becameIdle.add(uidRec);
}
+ } else {
+ if (uidRec.isIdle()) {
+ uidChange |= UidRecord.CHANGE_ACTIVE;
+ EventLogTags.writeAmUidActive(uidRec.getUid());
+ uidRec.setIdle(false);
+ }
+ uidRec.setLastBackgroundTime(0);
}
- if (uidRec.isIdle() && !uidRec.isSetIdle()) {
- uidChange = UidRecord.CHANGE_IDLE;
- becameIdle.add(uidRec);
+ final boolean wasCached = uidRec.getSetProcState()
+ > ActivityManager.PROCESS_STATE_RECEIVER;
+ final boolean isCached = uidRec.getCurProcState()
+ > ActivityManager.PROCESS_STATE_RECEIVER;
+ if (wasCached != isCached
+ || uidRec.getSetProcState() == PROCESS_STATE_NONEXISTENT) {
+ uidChange |= isCached ? UidRecord.CHANGE_CACHED :
+ UidRecord.CHANGE_UNCACHED;
}
- } else {
- if (uidRec.isIdle()) {
- uidChange = UidRecord.CHANGE_ACTIVE;
- EventLogTags.writeAmUidActive(uidRec.getUid());
- uidRec.setIdle(false);
+ if (uidRec.getSetCapability() != uidRec.getCurCapability()) {
+ uidChange |= UidRecord.CHANGE_CAPABILITY;
+ }
+ if (uidRec.getSetProcState() != uidRec.getCurProcState()) {
+ uidChange |= UidRecord.CHANGE_PROCSTATE;
+ }
+ if (uidRec.getProcAdjChanged()) {
+ uidChange |= UidRecord.CHANGE_PROCADJ;
+ }
+ uidRec.setSetProcState(uidRec.getCurProcState());
+ uidRec.setSetCapability(uidRec.getCurCapability());
+ uidRec.setSetAllowListed(uidRec.isCurAllowListed());
+ uidRec.setSetIdle(uidRec.isIdle());
+ uidRec.clearProcAdjChanged();
+ if ((uidChange & UidRecord.CHANGE_PROCSTATE) != 0
+ || (uidChange & UidRecord.CHANGE_CAPABILITY) != 0) {
+ mService.mAtmInternal.onUidProcStateChanged(
+ uidRec.getUid(), uidRec.getSetProcState());
+ }
+ if (uidChange != 0) {
+ mService.enqueueUidChangeLocked(uidRec, -1, uidChange);
+ }
+ if ((uidChange & UidRecord.CHANGE_PROCSTATE) != 0
+ || (uidChange & UidRecord.CHANGE_CAPABILITY) != 0) {
+ mService.noteUidProcessState(uidRec.getUid(), uidRec.getCurProcState(),
+ uidRec.getCurCapability());
+ }
+ if (uidRec.hasForegroundServices()) {
+ mService.mServices.foregroundServiceProcStateChangedLocked(uidRec);
}
- uidRec.setLastBackgroundTime(0);
- }
- final boolean wasCached = uidRec.getSetProcState()
- > ActivityManager.PROCESS_STATE_RECEIVER;
- final boolean isCached = uidRec.getCurProcState()
- > ActivityManager.PROCESS_STATE_RECEIVER;
- if (wasCached != isCached
- || uidRec.getSetProcState() == PROCESS_STATE_NONEXISTENT) {
- uidChange |= isCached ? UidRecord.CHANGE_CACHED : UidRecord.CHANGE_UNCACHED;
- }
- if (uidRec.getSetCapability() != uidRec.getCurCapability()) {
- uidChange |= UidRecord.CHANGE_CAPABILITY;
- }
- uidRec.setSetProcState(uidRec.getCurProcState());
- uidRec.setSetCapability(uidRec.getCurCapability());
- uidRec.setSetAllowListed(uidRec.isCurAllowListed());
- uidRec.setSetIdle(uidRec.isIdle());
- mService.mAtmInternal.onUidProcStateChanged(
- uidRec.getUid(), uidRec.getSetProcState());
- mService.enqueueUidChangeLocked(uidRec, -1, uidChange);
- mService.noteUidProcessState(uidRec.getUid(), uidRec.getCurProcState(),
- uidRec.getCurCapability());
- if (uidRec.hasForegroundServices()) {
- mService.mServices.foregroundServiceProcStateChangedLocked(uidRec);
}
}
mService.mInternal.deletePendingTopUid(uidRec.getUid(), nowElapsed);
@@ -2528,6 +2549,7 @@ public class OomAdjuster {
long nowElapsed) {
boolean success = true;
final ProcessStateRecord state = app.mState;
+ final UidRecord uidRec = app.getUidRecord();
if (state.getCurRawAdj() != state.getSetRawAdj()) {
state.setSetRawAdj(state.getCurRawAdj());
@@ -2566,6 +2588,9 @@ public class OomAdjuster {
reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
}
state.setSetAdj(state.getCurAdj());
+ if (uidRec != null) {
+ uidRec.noteProcAdjChanged();
+ }
state.setVerifiedAdj(ProcessList.INVALID_ADJ);
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 253686c2602d..6629a3018f81 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -180,22 +180,22 @@ public final class ProcessList {
// OOM adjustments for processes in various states:
// Uninitialized value for any major or minor adj fields
- static final int INVALID_ADJ = -10000;
+ public static final int INVALID_ADJ = -10000;
// Adjustment used in certain places where we don't know it yet.
// (Generally this is something that is going to be cached, but we
// don't know the exact value in the cached range to assign yet.)
- static final int UNKNOWN_ADJ = 1001;
+ public static final int UNKNOWN_ADJ = 1001;
// This is a process only hosting activities that are not visible,
// so it can be killed without any disruption.
- static final int CACHED_APP_MAX_ADJ = 999;
- static final int CACHED_APP_MIN_ADJ = 900;
+ public static final int CACHED_APP_MAX_ADJ = 999;
+ public static final int CACHED_APP_MIN_ADJ = 900;
// This is the oom_adj level that we allow to die first. This cannot be equal to
// CACHED_APP_MAX_ADJ unless processes are actively being assigned an oom_score_adj of
// CACHED_APP_MAX_ADJ.
- static final int CACHED_APP_LMK_FIRST_ADJ = 950;
+ public static final int CACHED_APP_LMK_FIRST_ADJ = 950;
// Number of levels we have available for different service connection group importance
// levels.
@@ -203,7 +203,7 @@ public final class ProcessList {
// The B list of SERVICE_ADJ -- these are the old and decrepit
// services that aren't as shiny and interesting as the ones in the A list.
- static final int SERVICE_B_ADJ = 800;
+ public static final int SERVICE_B_ADJ = 800;
// This is the process of the previous application that the user was in.
// This process is kept above other things, because it is very common to
@@ -211,68 +211,68 @@ public final class ProcessList {
// task switch (toggling between the two top recent apps) as well as normal
// UI flow such as clicking on a URI in the e-mail app to view in the browser,
// and then pressing back to return to e-mail.
- static final int PREVIOUS_APP_ADJ = 700;
+ public static final int PREVIOUS_APP_ADJ = 700;
// This is a process holding the home application -- we want to try
// avoiding killing it, even if it would normally be in the background,
// because the user interacts with it so much.
- static final int HOME_APP_ADJ = 600;
+ public static final int HOME_APP_ADJ = 600;
// This is a process holding an application service -- killing it will not
// have much of an impact as far as the user is concerned.
- static final int SERVICE_ADJ = 500;
+ public static final int SERVICE_ADJ = 500;
// This is a process with a heavy-weight application. It is in the
// background, but we want to try to avoid killing it. Value set in
// system/rootdir/init.rc on startup.
- static final int HEAVY_WEIGHT_APP_ADJ = 400;
+ public static final int HEAVY_WEIGHT_APP_ADJ = 400;
// This is a process currently hosting a backup operation. Killing it
// is not entirely fatal but is generally a bad idea.
- static final int BACKUP_APP_ADJ = 300;
+ public static final int BACKUP_APP_ADJ = 300;
// This is a process bound by the system (or other app) that's more important than services but
// not so perceptible that it affects the user immediately if killed.
- static final int PERCEPTIBLE_LOW_APP_ADJ = 250;
+ public static final int PERCEPTIBLE_LOW_APP_ADJ = 250;
// This is a process hosting services that are not perceptible to the user but the
// client (system) binding to it requested to treat it as if it is perceptible and avoid killing
// it if possible.
- static final int PERCEPTIBLE_MEDIUM_APP_ADJ = 225;
+ public static final int PERCEPTIBLE_MEDIUM_APP_ADJ = 225;
// This is a process only hosting components that are perceptible to the
// user, and we really want to avoid killing them, but they are not
// immediately visible. An example is background music playback.
- static final int PERCEPTIBLE_APP_ADJ = 200;
+ public static final int PERCEPTIBLE_APP_ADJ = 200;
// This is a process only hosting activities that are visible to the
// user, so we'd prefer they don't disappear.
- static final int VISIBLE_APP_ADJ = 100;
+ public static final int VISIBLE_APP_ADJ = 100;
static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;
// This is a process that was recently TOP and moved to FGS. Continue to treat it almost
// like a foreground app for a while.
// @see TOP_TO_FGS_GRACE_PERIOD
- static final int PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50;
+ public static final int PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50;
// This is the process running the current foreground app. We'd really
// rather not kill it!
- static final int FOREGROUND_APP_ADJ = 0;
+ public static final int FOREGROUND_APP_ADJ = 0;
// This is a process that the system or a persistent process has bound to,
// and indicated it is important.
- static final int PERSISTENT_SERVICE_ADJ = -700;
+ public static final int PERSISTENT_SERVICE_ADJ = -700;
// This is a system persistent process, such as telephony. Definitely
// don't want to kill it, but doing so is not completely fatal.
- static final int PERSISTENT_PROC_ADJ = -800;
+ public static final int PERSISTENT_PROC_ADJ = -800;
// The system process runs at the default adjustment.
- static final int SYSTEM_ADJ = -900;
+ public static final int SYSTEM_ADJ = -900;
// Special code for native processes that are not being managed by the system (so
// don't have an oom adj assigned by the system).
- static final int NATIVE_ADJ = -1000;
+ public static final int NATIVE_ADJ = -1000;
// Memory pages are 4K.
static final int PAGE_SIZE = 4 * 1024;
@@ -3031,7 +3031,7 @@ public final class ProcessList {
Slog.i(TAG_UID_OBSERVERS, "No more processes in " + uidRecord);
}
mService.enqueueUidChangeLocked(uidRecord, -1,
- UidRecord.CHANGE_GONE);
+ UidRecord.CHANGE_GONE | UidRecord.CHANGE_PROCSTATE);
EventLogTags.writeAmUidStopped(uid);
mActiveUids.remove(uid);
mService.mFgsStartTempAllowList.removeUid(record.info.uid);
@@ -5383,5 +5383,9 @@ public final class ProcessList {
@Override
public void onUidCachedChanged(int uid, boolean cached) {
}
+
+ @Override
+ public void onUidProcAdjChanged(int uid) {
+ }
};
}
diff --git a/services/core/java/com/android/server/am/UidObserverController.java b/services/core/java/com/android/server/am/UidObserverController.java
index f6a184119bb4..e42dac46d7c7 100644
--- a/services/core/java/com/android/server/am/UidObserverController.java
+++ b/services/core/java/com/android/server/am/UidObserverController.java
@@ -154,6 +154,12 @@ public class UidObserverController {
if ((pendingChange & UidRecord.CHANGE_CAPABILITY) != 0) {
currentChange |= UidRecord.CHANGE_CAPABILITY;
}
+ if ((pendingChange & UidRecord.CHANGE_PROCSTATE) != 0) {
+ currentChange |= UidRecord.CHANGE_PROCSTATE;
+ }
+ if ((pendingChange & UidRecord.CHANGE_PROCADJ) != 0) {
+ currentChange |= UidRecord.CHANGE_PROCADJ;
+ }
return currentChange;
}
@@ -245,6 +251,7 @@ public class UidObserverController {
try {
for (int j = 0; j < changesSize; j++) {
final ChangeRecord item = mActiveUidChanges[j];
+ final long start = SystemClock.uptimeMillis();
final int change = item.change;
if (change == UidRecord.CHANGE_PROCSTATE
&& (reg.mWhich & ActivityManager.UID_OBSERVER_PROCSTATE) == 0) {
@@ -252,7 +259,12 @@ public class UidObserverController {
// interested in all proc state changes.
continue;
}
- final long start = SystemClock.uptimeMillis();
+ if (change == UidRecord.CHANGE_PROCADJ
+ && (reg.mWhich & ActivityManager.UID_OBSERVER_PROC_OOM_ADJ) == 0) {
+ // No-op common case: no significant change, the observer is not
+ // interested in proc adj changes.
+ continue;
+ }
if ((change & UidRecord.CHANGE_IDLE) != 0) {
if ((reg.mWhich & ActivityManager.UID_OBSERVER_IDLE) != 0) {
if (DEBUG_UID_OBSERVERS) {
@@ -319,7 +331,12 @@ public class UidObserverController {
reg.mLastProcStates.put(item.uid, item.procState);
}
observer.onUidStateChanged(item.uid, item.procState,
- item.procStateSeq, item.capability);
+ item.procStateSeq,
+ item.capability);
+ }
+ if ((reg.mWhich & ActivityManager.UID_OBSERVER_PROC_OOM_ADJ) != 0
+ && (change & UidRecord.CHANGE_PROCADJ) != 0) {
+ observer.onUidProcAdjChanged(item.uid);
}
}
final int duration = (int) (SystemClock.uptimeMillis() - start);
@@ -440,6 +457,7 @@ public class UidObserverController {
ActivityManager.UID_OBSERVER_GONE,
ActivityManager.UID_OBSERVER_PROCSTATE,
ActivityManager.UID_OBSERVER_CAPABILITY,
+ ActivityManager.UID_OBSERVER_PROC_OOM_ADJ,
};
private static final int[] PROTO_ENUMS = new int[]{
ActivityManagerProto.UID_OBSERVER_FLAG_IDLE,
@@ -447,6 +465,7 @@ public class UidObserverController {
ActivityManagerProto.UID_OBSERVER_FLAG_GONE,
ActivityManagerProto.UID_OBSERVER_FLAG_PROCSTATE,
ActivityManagerProto.UID_OBSERVER_FLAG_CAPABILITY,
+ ActivityManagerProto.UID_OBSERVER_FLAG_PROC_OOM_ADJ,
};
UidObserverRegistration(int uid, @NonNull String pkg, int which, int cutpoint) {
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index 6101e267effc..5c78d1eb5ff2 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -48,6 +48,9 @@ public final class UidRecord {
private int mSetProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
@CompositeRWLock({"mService", "mProcLock"})
+ private boolean mProcAdjChanged;
+
+ @CompositeRWLock({"mService", "mProcLock"})
private int mCurCapability;
@CompositeRWLock({"mService", "mProcLock"})
@@ -117,13 +120,17 @@ public final class UidRecord {
*/
final Object networkStateLock = new Object();
- static final int CHANGE_PROCSTATE = 0;
- static final int CHANGE_GONE = 1<<0;
- static final int CHANGE_IDLE = 1<<1;
- static final int CHANGE_ACTIVE = 1<<2;
- static final int CHANGE_CACHED = 1<<3;
- static final int CHANGE_UNCACHED = 1<<4;
- static final int CHANGE_CAPABILITY = 1<<5;
+ /*
+ * Change bitmask flags.
+ */
+ static final int CHANGE_GONE = 1 << 0;
+ static final int CHANGE_IDLE = 1 << 1;
+ static final int CHANGE_ACTIVE = 1 << 2;
+ static final int CHANGE_CACHED = 1 << 3;
+ static final int CHANGE_UNCACHED = 1 << 4;
+ static final int CHANGE_CAPABILITY = 1 << 5;
+ static final int CHANGE_PROCADJ = 1 << 6;
+ static final int CHANGE_PROCSTATE = 1 << 31;
// Keep the enum lists in sync
private static int[] ORIG_ENUMS = new int[] {
@@ -133,6 +140,7 @@ public final class UidRecord {
CHANGE_CACHED,
CHANGE_UNCACHED,
CHANGE_CAPABILITY,
+ CHANGE_PROCSTATE,
};
private static int[] PROTO_ENUMS = new int[] {
UidRecordProto.CHANGE_GONE,
@@ -141,6 +149,7 @@ public final class UidRecord {
UidRecordProto.CHANGE_CACHED,
UidRecordProto.CHANGE_UNCACHED,
UidRecordProto.CHANGE_CAPABILITY,
+ UidRecordProto.CHANGE_PROCSTATE,
};
// UidObserverController is the only thing that should modify this.
@@ -181,6 +190,21 @@ public final class UidRecord {
mSetProcState = setProcState;
}
+ @GuardedBy({"mService", "mProcLock"})
+ void noteProcAdjChanged() {
+ mProcAdjChanged = true;
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ void clearProcAdjChanged() {
+ mProcAdjChanged = false;
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ boolean getProcAdjChanged() {
+ return mProcAdjChanged;
+ }
+
@GuardedBy(anyOf = {"mService", "mProcLock"})
int getCurCapability() {
return mCurCapability;
@@ -417,6 +441,18 @@ public final class UidRecord {
}
sb.append("uncached");
}
+ if ((mLastReportedChange & CHANGE_PROCSTATE) != 0) {
+ if (printed) {
+ sb.append("|");
+ }
+ sb.append("procstate");
+ }
+ if ((mLastReportedChange & CHANGE_PROCADJ) != 0) {
+ if (printed) {
+ sb.append("|");
+ }
+ sb.append("procadj");
+ }
}
sb.append(" procs:");
sb.append(mNumProcs);
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
index 42a7423725a3..766283b92d91 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
@@ -217,9 +217,13 @@ final class AmbientContextManagerPerUserService extends
RemoteCallback detectionResultCallback, RemoteCallback statusCallback) {
Slog.d(TAG, "Requested detection of " + request.getEventTypes());
synchronized (mLock) {
- ensureRemoteServiceInitiated();
- mRemoteService.startDetection(request, callingPackage, detectionResultCallback,
- statusCallback);
+ if (setUpServiceIfNeeded()) {
+ ensureRemoteServiceInitiated();
+ mRemoteService.startDetection(request, callingPackage, detectionResultCallback,
+ statusCallback);
+ } else {
+ Slog.w(TAG, "No valid component found for AmbientContextDetectionService");
+ }
}
}
@@ -371,8 +375,10 @@ final class AmbientContextManagerPerUserService extends
void stopDetection(String packageName) {
Slog.d(TAG, "Stop detection for " + packageName);
synchronized (mLock) {
- ensureRemoteServiceInitiated();
- mRemoteService.stopDetection(packageName);
+ if (mComponentName != null) {
+ ensureRemoteServiceInitiated();
+ mRemoteService.stopDetection(packageName);
+ }
}
}
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
index 2cdf7e7c7133..cfca7ec6f568 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
@@ -42,6 +42,7 @@ import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.infra.AbstractMasterSystemService;
import com.android.server.infra.FrameworkResourcesServiceNameResolver;
+import com.android.server.pm.KnownPackages;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -117,7 +118,7 @@ public class AmbientContextManagerService extends
public static boolean isDetectionServiceConfigured() {
final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
final String[] packageNames = pmi.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_AMBIENT_CONTEXT_DETECTION, UserHandle.USER_SYSTEM);
+ KnownPackages.PACKAGE_AMBIENT_CONTEXT_DETECTION, UserHandle.USER_SYSTEM);
boolean isServiceConfigured = (packageNames.length != 0);
Slog.i(TAG, "Detection service configured: " + isServiceConfigured);
return isServiceConfigured;
@@ -249,6 +250,8 @@ public class AmbientContextManagerService extends
Objects.requireNonNull(eventTypes);
Objects.requireNonNull(callingPackage);
assertCalledByPackageOwner(callingPackage);
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
mService.onStartConsentActivity(eventTypes, callingPackage);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d7755810f37b..517ff82d9fd2 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -905,6 +905,9 @@ public class AudioService extends IAudioService.Stub
disableAudioForUid(cached, uid);
}
+ @Override public void onUidProcAdjChanged(int uid) {
+ }
+
private void disableAudioForUid(boolean disable, int uid) {
queueMsgUnderWakeLock(mAudioHandler, MSG_DISABLE_AUDIO_FOR_UID,
disable ? 1 : 0 /* arg1 */, uid /* arg2 */,
@@ -10734,7 +10737,8 @@ public class AudioService extends IAudioService.Stub
return mMediaFocusControl.sendFocusLoss(focusLoser);
}
- private static final String[] HAL_VERSIONS = new String[] {"7.1", "7.0", "6.0", "4.0", "2.0"};
+ private static final String[] HAL_VERSIONS =
+ new String[] {"7.1", "7.0", "6.0", "5.0", "4.0", "2.0"};
/** @see AudioManager#getHalVersion */
public @Nullable String getHalVersion() {
diff --git a/services/core/java/com/android/server/biometrics/BiometricSensor.java b/services/core/java/com/android/server/biometrics/BiometricSensor.java
index 7166783f0b23..937e3f8f8668 100644
--- a/services/core/java/com/android/server/biometrics/BiometricSensor.java
+++ b/services/core/java/com/android/server/biometrics/BiometricSensor.java
@@ -22,10 +22,8 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricConstants;
-import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricSensorReceiver;
-import android.hardware.biometrics.SensorPropertiesInternal;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
@@ -149,7 +147,7 @@ public abstract class BiometricSensor {
* Returns the actual strength, taking any updated strengths into effect. Since more bits
* means lower strength, the resulting strength is never stronger than the OEM's configured
* strength.
- * @return a bitfield, see {@link BiometricManager.Authenticators}
+ * @return a bitfield, see {@link android.hardware.biometrics.BiometricManager.Authenticators}
*/
@Authenticators.Types int getCurrentStrength() {
return oemStrength | mUpdatedStrength;
@@ -169,27 +167,19 @@ public abstract class BiometricSensor {
* @param newStrength
*/
void updateStrength(@Authenticators.Types int newStrength) {
- String log = "updateStrength: Before(" + toString() + ")";
+ String log = "updateStrength: Before(" + this + ")";
mUpdatedStrength = newStrength;
- log += " After(" + toString() + ")";
+ log += " After(" + this + ")";
Slog.d(TAG, log);
}
@Override
public String toString() {
- SensorPropertiesInternal properties = null;
- try {
- properties = impl.getSensorProperties(mContext.getOpPackageName());
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- }
-
return "ID(" + id + ")"
+ ", oemStrength: " + oemStrength
+ ", updatedStrength: " + mUpdatedStrength
+ ", modality " + modality
+ ", state: " + mSensorState
- + ", cookie: " + mCookie
- + ", props: " + properties;
+ + ", cookie: " + mCookie;
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index e8d8fb828542..5727ffc468df 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -280,15 +280,26 @@ public class FingerprintService extends SystemService {
@SuppressWarnings("deprecation")
@Override // Binder call
- public long authenticate(final IBinder token, final long operationId,
- final int sensorId, final int userId, final IFingerprintServiceReceiver receiver,
- final String opPackageName, boolean ignoreEnrollmentState) {
+ public long authenticate(
+ final IBinder token,
+ final long operationId,
+ final int sensorId,
+ final int userId,
+ final IFingerprintServiceReceiver receiver,
+ final String opPackageName,
+ final String attributionTag,
+ boolean ignoreEnrollmentState) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
- if (!canUseFingerprint(opPackageName, true /* requireForeground */, callingUid,
- callingPid, callingUserId)) {
+ if (!canUseFingerprint(
+ opPackageName,
+ attributionTag,
+ true /* requireForeground */,
+ callingUid,
+ callingPid,
+ callingUserId)) {
Slog.w(TAG, "Authenticate rejecting package: " + opPackageName);
return -1;
}
@@ -487,16 +498,23 @@ public class FingerprintService extends SystemService {
provider.startPreparedClient(sensorId, cookie);
}
-
@Override // Binder call
- public void cancelAuthentication(final IBinder token, final String opPackageName,
+ public void cancelAuthentication(
+ final IBinder token,
+ final String opPackageName,
+ final String attributionTag,
long requestId) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
- if (!canUseFingerprint(opPackageName, true /* requireForeground */, callingUid,
- callingPid, callingUserId)) {
+ if (!canUseFingerprint(
+ opPackageName,
+ attributionTag,
+ true /* requireForeground */,
+ callingUid,
+ callingPid,
+ callingUserId)) {
Slog.w(TAG, "cancelAuthentication rejecting package: " + opPackageName);
return;
}
@@ -645,9 +663,13 @@ public class FingerprintService extends SystemService {
}
@Override // Binder call
- public boolean isHardwareDetectedDeprecated(String opPackageName) {
- if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
- Binder.getCallingUid(), Binder.getCallingPid(),
+ public boolean isHardwareDetectedDeprecated(String opPackageName, String attributionTag) {
+ if (!canUseFingerprint(
+ opPackageName,
+ attributionTag,
+ false /* foregroundOnly */,
+ Binder.getCallingUid(),
+ Binder.getCallingPid(),
UserHandle.getCallingUserId())) {
return false;
}
@@ -696,9 +718,14 @@ public class FingerprintService extends SystemService {
}
@Override // Binder call
- public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
- if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
- Binder.getCallingUid(), Binder.getCallingPid(),
+ public List<Fingerprint> getEnrolledFingerprints(
+ int userId, String opPackageName, String attributionTag) {
+ if (!canUseFingerprint(
+ opPackageName,
+ attributionTag,
+ false /* foregroundOnly */,
+ Binder.getCallingUid(),
+ Binder.getCallingPid(),
UserHandle.getCallingUserId())) {
return Collections.emptyList();
}
@@ -711,9 +738,14 @@ public class FingerprintService extends SystemService {
}
@Override // Binder call
- public boolean hasEnrolledFingerprintsDeprecated(int userId, String opPackageName) {
- if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
- Binder.getCallingUid(), Binder.getCallingPid(),
+ public boolean hasEnrolledFingerprintsDeprecated(
+ int userId, String opPackageName, String attributionTag) {
+ if (!canUseFingerprint(
+ opPackageName,
+ attributionTag,
+ false /* foregroundOnly */,
+ Binder.getCallingUid(),
+ Binder.getCallingPid(),
UserHandle.getCallingUserId())) {
return false;
}
@@ -1093,12 +1125,15 @@ public class FingerprintService extends SystemService {
return provider.second.getEnrolledFingerprints(provider.first, userId);
}
- /**
- * Checks for public API invocations to ensure that permissions, etc are granted/correct.
- */
+ /** Checks for public API invocations to ensure that permissions, etc are granted/correct. */
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
- private boolean canUseFingerprint(String opPackageName, boolean requireForeground, int uid,
- int pid, int userId) {
+ private boolean canUseFingerprint(
+ String opPackageName,
+ String attributionTag,
+ boolean requireForeground,
+ int uid,
+ int pid,
+ int userId) {
if (getContext().checkCallingPermission(USE_FINGERPRINT)
!= PackageManager.PERMISSION_GRANTED) {
Utils.checkPermission(getContext(), USE_BIOMETRIC);
@@ -1114,7 +1149,7 @@ public class FingerprintService extends SystemService {
Slog.w(TAG, "Rejecting " + opPackageName + "; not a current user or profile");
return false;
}
- if (!checkAppOps(uid, opPackageName)) {
+ if (!checkAppOps(uid, opPackageName, attributionTag)) {
Slog.w(TAG, "Rejecting " + opPackageName + "; permission denied");
return false;
}
@@ -1125,12 +1160,13 @@ public class FingerprintService extends SystemService {
return true;
}
- private boolean checkAppOps(int uid, String opPackageName) {
+ private boolean checkAppOps(int uid, String opPackageName, String attributionTag) {
boolean appOpsOk = false;
- if (mAppOps.noteOp(AppOpsManager.OP_USE_BIOMETRIC, uid, opPackageName)
+ if (mAppOps.noteOp(AppOpsManager.OP_USE_BIOMETRIC, uid, opPackageName, attributionTag, null)
== AppOpsManager.MODE_ALLOWED) {
appOpsOk = true;
- } else if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName)
+ } else if (mAppOps.noteOp(
+ AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName, attributionTag, null)
== AppOpsManager.MODE_ALLOWED) {
appOpsOk = true;
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index a6da4a6a4260..35217dba7c28 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -2692,6 +2692,9 @@ public class Vpn {
return; // VPN has been shut down.
}
+ // Clear mInterface to prevent Ikev2VpnRunner being cleared when
+ // interfaceRemoved() is called.
+ mInterface = null;
// Without MOBIKE, we have no way to seamlessly migrate. Close on old
// (non-default) network, and start the new one.
resetIkeState();
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 82e1efd1b884..c88e3eb6d507 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -446,14 +446,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary adjustment set.
private float mTemporaryAutoBrightnessAdjustment;
- // Whether reduce bright colors (rbc) has been turned on, or a change in strength has been
- // requested. We want to retain the current backlight level when rbc is toggled, since rbc
- // additionally makes the screen appear dimmer using screen colors rather than backlight levels,
- // and therefore we don't actually want to compensate for this by then in/decreasing the
- // backlight when toggling this feature.
- // This should be false during system start up.
- private boolean mPendingRbcOnOrChanged = false;
-
// Animators.
private ObjectAnimator mColorFadeOnAnimator;
private ObjectAnimator mColorFadeOffAnimator;
@@ -572,20 +564,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
@Override
public void onReduceBrightColorsActivationChanged(boolean activated,
boolean userInitiated) {
- applyReduceBrightColorsSplineAdjustment(
- /* rbcStrengthChanged= */ false, activated);
+ applyReduceBrightColorsSplineAdjustment();
}
@Override
public void onReduceBrightColorsStrengthChanged(int strength) {
- applyReduceBrightColorsSplineAdjustment(
- /* rbcStrengthChanged= */ true, /* justActivated= */ false);
+ applyReduceBrightColorsSplineAdjustment();
}
});
if (active) {
- applyReduceBrightColorsSplineAdjustment(
- /* rbcStrengthChanged= */ false, /* justActivated= */ false);
+ applyReduceBrightColorsSplineAdjustment();
}
} else {
mCdsi = null;
@@ -615,15 +604,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
- private void applyReduceBrightColorsSplineAdjustment(
- boolean rbcStrengthChanged, boolean justActivated) {
- final int strengthChanged = rbcStrengthChanged ? 1 : 0;
- final int activated = justActivated ? 1 : 0;
- mHandler.obtainMessage(MSG_UPDATE_RBC, strengthChanged, activated).sendToTarget();
+ private void applyReduceBrightColorsSplineAdjustment() {
+ mHandler.obtainMessage(MSG_UPDATE_RBC).sendToTarget();
sendUpdatePowerState();
}
- private void handleRbcChanged(boolean strengthChanged, boolean justActivated) {
+ private void handleRbcChanged() {
if (mAutomaticBrightnessController == null) {
return;
}
@@ -642,12 +628,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mAutomaticBrightnessController.recalculateSplines(mCdsi.isReduceBrightColorsActivated(),
adjustedNits);
- mPendingRbcOnOrChanged = strengthChanged || justActivated;
- // Reset model if strength changed OR rbc is turned off
- if ((strengthChanged || !justActivated) && mAutomaticBrightnessController != null) {
- mAutomaticBrightnessController.resetShortTermModel();
- }
+ // If rbc is turned on, off or there is a change in strength, we want to reset the short
+ // term model. Since the nits range at which brightness now operates has changed due to
+ // RBC/strength change, any short term model based on the previous range should be
+ // invalidated.
+ mAutomaticBrightnessController.resetShortTermModel();
}
/**
@@ -1019,8 +1005,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private void reloadReduceBrightColours() {
if (mCdsi != null && mCdsi.isReduceBrightColorsActivated()) {
- applyReduceBrightColorsSplineAdjustment(
- /* rbcStrengthChanged= */ false, /* justActivated= */ false);
+ applyReduceBrightColorsSplineAdjustment();
}
}
@@ -2285,23 +2270,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
// We want to return true if the user has set the screen brightness.
- // If they have just turned RBC on (and therefore added that interaction to the curve),
- // or changed the brightness another way, then we should return true.
+ // RBC on, off, and intensity changes will return false.
+ // Slider interactions whilst in RBC will return true, just as when in non-rbc.
private boolean updateUserSetScreenBrightness() {
- final boolean treatAsIfUserChanged = mPendingRbcOnOrChanged;
- if (treatAsIfUserChanged && !Float.isNaN(mCurrentScreenBrightnessSetting)) {
- mLastUserSetScreenBrightness = mCurrentScreenBrightnessSetting;
- }
- mPendingRbcOnOrChanged = false;
-
if ((Float.isNaN(mPendingScreenBrightnessSetting)
|| mPendingScreenBrightnessSetting < 0.0f)) {
- return treatAsIfUserChanged;
+ return false;
}
if (mCurrentScreenBrightnessSetting == mPendingScreenBrightnessSetting) {
mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
- return treatAsIfUserChanged;
+ return false;
}
setCurrentScreenBrightness(mPendingScreenBrightnessSetting);
mLastUserSetScreenBrightness = mPendingScreenBrightnessSetting;
@@ -2691,9 +2670,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
break;
case MSG_UPDATE_RBC:
- final int strengthChanged = msg.arg1;
- final int justActivated = msg.arg2;
- handleRbcChanged(strengthChanged == 1, justActivated == 1);
+ handleRbcChanged();
break;
case MSG_BRIGHTNESS_RAMP_DONE:
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index e3ecf498fbb0..b7ad4ed4f98d 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -227,6 +227,8 @@ final class LogicalDisplay {
info.largestNominalAppHeight = mOverrideDisplayInfo.largestNominalAppHeight;
info.logicalWidth = mOverrideDisplayInfo.logicalWidth;
info.logicalHeight = mOverrideDisplayInfo.logicalHeight;
+ info.physicalXDpi = mOverrideDisplayInfo.physicalXDpi;
+ info.physicalYDpi = mOverrideDisplayInfo.physicalYDpi;
info.rotation = mOverrideDisplayInfo.rotation;
info.displayCutout = mOverrideDisplayInfo.displayCutout;
info.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
diff --git a/services/core/java/com/android/server/display/OWNERS b/services/core/java/com/android/server/display/OWNERS
index 09d96be43a43..8e3460175158 100644
--- a/services/core/java/com/android/server/display/OWNERS
+++ b/services/core/java/com/android/server/display/OWNERS
@@ -3,5 +3,6 @@ dangittik@google.com
hackbod@google.com
ogunwale@google.com
santoscordon@google.com
+flc@google.com
per-file ColorDisplayService.java=christyfranks@google.com
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 50f5536d9f4b..436c434ccbca 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -47,8 +47,7 @@ import android.service.dreams.IDreamManager;
import android.util.Slog;
import android.view.Display;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.UiEvent;
+import com.android.internal.R;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.util.DumpUtils;
@@ -82,6 +81,7 @@ public final class DreamManagerService extends SystemService {
private final PowerManager.WakeLock mDozeWakeLock;
private final ActivityTaskManagerInternal mAtmInternal;
private final UiEventLogger mUiEventLogger;
+ private final DreamUiEventLogger mDreamUiEventLogger;
private final ComponentName mAmbientDisplayComponent;
private Binder mCurrentDreamToken;
@@ -99,26 +99,6 @@ public final class DreamManagerService extends SystemService {
private AmbientDisplayConfiguration mDozeConfig;
- @VisibleForTesting
- public enum DreamManagerEvent implements UiEventLogger.UiEventEnum {
- @UiEvent(doc = "The screensaver has started.")
- DREAM_START(577),
-
- @UiEvent(doc = "The screensaver has stopped.")
- DREAM_STOP(578);
-
- private final int mId;
-
- DreamManagerEvent(int id) {
- mId = id;
- }
-
- @Override
- public int getId() {
- return mId;
- }
- }
-
public DreamManagerService(Context context) {
super(context);
mContext = context;
@@ -131,6 +111,8 @@ public final class DreamManagerService extends SystemService {
mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
mDozeConfig = new AmbientDisplayConfiguration(mContext);
mUiEventLogger = new UiEventLoggerImpl();
+ mDreamUiEventLogger = new DreamUiEventLoggerImpl(
+ mContext.getResources().getString(R.string.config_loggable_dream_prefix));
AmbientDisplayConfiguration adc = new AmbientDisplayConfiguration(mContext);
mAmbientDisplayComponent = ComponentName.unflattenFromString(adc.ambientDisplayComponent());
}
@@ -417,7 +399,10 @@ public final class DreamManagerService extends SystemService {
mCurrentDreamUserId = userId;
if (!mCurrentDreamName.equals(mAmbientDisplayComponent)) {
- mUiEventLogger.log(DreamManagerEvent.DREAM_START);
+ // TODO(b/213906448): Remove when metrics based on new atom are fully rolled out.
+ mUiEventLogger.log(DreamUiEventLogger.DreamUiEventEnum.DREAM_START);
+ mDreamUiEventLogger.log(DreamUiEventLogger.DreamUiEventEnum.DREAM_START,
+ mCurrentDreamName.flattenToString());
}
PowerManager.WakeLock wakeLock = mPowerManager
@@ -453,7 +438,10 @@ public final class DreamManagerService extends SystemService {
private void cleanupDreamLocked() {
if (!mCurrentDreamName.equals(mAmbientDisplayComponent)) {
- mUiEventLogger.log(DreamManagerEvent.DREAM_STOP);
+ // TODO(b/213906448): Remove when metrics based on new atom are fully rolled out.
+ mUiEventLogger.log(DreamUiEventLogger.DreamUiEventEnum.DREAM_STOP);
+ mDreamUiEventLogger.log(DreamUiEventLogger.DreamUiEventEnum.DREAM_STOP,
+ mCurrentDreamName.flattenToString());
}
mCurrentDreamToken = null;
mCurrentDreamName = null;
diff --git a/services/core/java/com/android/server/dreams/DreamUiEventLogger.java b/services/core/java/com/android/server/dreams/DreamUiEventLogger.java
new file mode 100644
index 000000000000..5eb4d1c65b25
--- /dev/null
+++ b/services/core/java/com/android/server/dreams/DreamUiEventLogger.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.dreams;
+
+import android.annotation.NonNull;
+
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+
+/**
+ * Logging interface for Dream UI events. Normal implementation is DreamUiEventLoggerImpl.
+ *
+ * See DreamUiEventReported atom in atoms.proto for more context.
+ * @hide
+ */
+public interface DreamUiEventLogger {
+ /** Put your Event IDs in enums that implement this interface, and document them using the
+ * UiEventEnum annotation.
+ * Event IDs must be globally unique. This will be enforced by tooling (forthcoming).
+ * OEMs should use event IDs above 100000 and below 1000000 (1 million).
+ */
+ enum DreamUiEventEnum implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "The screensaver has started.")
+ DREAM_START(577),
+
+ @UiEvent(doc = "The screensaver has stopped.")
+ DREAM_STOP(578);
+
+ private final int mId;
+
+ DreamUiEventEnum(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+ }
+
+ /**
+ * Log a simple event with dream component name, with no package information. Does nothing if
+ * event.getId() <= 0.
+ * @param event an enum implementing UiEventEnum interface.
+ * @param dreamComponentName the component name of the dream in use.
+ */
+ void log(@NonNull UiEventLogger.UiEventEnum event, @NonNull String dreamComponentName);
+}
diff --git a/services/core/java/com/android/server/dreams/DreamUiEventLoggerImpl.java b/services/core/java/com/android/server/dreams/DreamUiEventLoggerImpl.java
new file mode 100644
index 000000000000..26ca74a8d808
--- /dev/null
+++ b/services/core/java/com/android/server/dreams/DreamUiEventLoggerImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 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.dreams;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.util.FrameworkStatsLog;
+
+/**
+ * Standard implementation of DreamUiEventLogger, writing to FrameworkStatsLog.
+ *
+ * See DreamUiEventReported atom in atoms.proto for more context.
+ * @hide
+ */
+public class DreamUiEventLoggerImpl implements DreamUiEventLogger {
+ final String mLoggableDreamPrefix;
+
+ DreamUiEventLoggerImpl(String loggableDreamPrefix) {
+ mLoggableDreamPrefix = loggableDreamPrefix;
+ }
+
+ @Override
+ public void log(UiEventLogger.UiEventEnum event, String dreamComponentName) {
+ final int eventID = event.getId();
+ if (eventID <= 0) {
+ return;
+ }
+ final boolean isFirstPartyDream =
+ mLoggableDreamPrefix.isEmpty() ? false : dreamComponentName.startsWith(
+ mLoggableDreamPrefix);
+ FrameworkStatsLog.write(FrameworkStatsLog.DREAM_UI_EVENT_REPORTED,
+ /* uid = 1 */ 0,
+ /* event_id = 2 */ eventID,
+ /* instance_id = 3 */ 0,
+ /* dream_component_name = 4 */ isFirstPartyDream ? dreamComponentName : "other");
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 27f64ecbe99a..ccb27eef2075 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -214,6 +214,7 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
} else {
// We'll not invalidate the active source on the hotplug event to pass CETC 11.2.2-2 ~ 3
getWakeLock().release();
+ mService.getHdmiCecNetwork().removeDevicesConnectedToPort(portId);
mDelayedStandbyHandler.removeCallbacksAndMessages(null);
mDelayedStandbyHandler.postDelayed(new DelayedStandbyRunnable(),
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index d249d578cf67..9212fb604721 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -1245,6 +1245,11 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
@ServiceThreadOnly
void onHotplug(int portId, boolean connected) {
assertRunOnServiceThread();
+
+ if (!connected) {
+ mService.getHdmiCecNetwork().removeCecSwitches(portId);
+ }
+
// Turning System Audio Mode off when the AVR is unlugged or standby.
// When the device is not unplugged but reawaken from standby, we check if the System
// Audio Control Feature is enabled or not then decide if turning SAM on/off accordingly.
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
index 185eaa92d511..8b6d16a171f5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
@@ -259,7 +259,10 @@ public class HdmiCecNetwork {
// The addition of a local device should not notify listeners
return;
}
- if (old == null) {
+ if (info.getPhysicalAddress() == HdmiDeviceInfo.PATH_INVALID) {
+ // Don't notify listeners of devices that haven't reported their physical address yet
+ return;
+ } else if (old == null || old.getPhysicalAddress() == HdmiDeviceInfo.PATH_INVALID) {
invokeDeviceEventListener(info,
HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
} else if (!old.equals(info)) {
@@ -286,7 +289,10 @@ public class HdmiCecNetwork {
assertRunOnServiceThread();
HdmiDeviceInfo old = addDeviceInfo(info);
- if (old == null) {
+ if (info.getPhysicalAddress() == HdmiDeviceInfo.PATH_INVALID) {
+ // Don't notify listeners of devices that haven't reported their physical address yet
+ return;
+ } else if (old == null || old.getPhysicalAddress() == HdmiDeviceInfo.PATH_INVALID) {
invokeDeviceEventListener(info,
HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
} else if (!old.equals(info)) {
@@ -360,10 +366,12 @@ public class HdmiCecNetwork {
// This only applies to TV devices.
// Returns true if the policy is set to true, and the device to check does not have
// a parent CEC device (which should be the CEC-enabled switch) in the list.
+ // Devices with an invalid physical address are assumed to NOT be connected to a legacy switch.
private boolean hideDevicesBehindLegacySwitch(HdmiDeviceInfo info) {
return isLocalDeviceAddress(Constants.ADDR_TV)
&& HdmiConfig.HIDE_DEVICES_BEHIND_LEGACY_SWITCH
- && !isConnectedToCecSwitch(info.getPhysicalAddress(), getCecSwitches());
+ && !isConnectedToCecSwitch(info.getPhysicalAddress(), getCecSwitches())
+ && info.getPhysicalAddress() != HdmiDeviceInfo.PATH_INVALID;
}
/**
@@ -377,6 +385,10 @@ public class HdmiCecNetwork {
HdmiDeviceInfo info = removeDeviceInfo(HdmiDeviceInfo.idForCecDevice(address));
localDevice.mCecMessageCache.flushMessagesFrom(address);
+ if (info.getPhysicalAddress() == HdmiDeviceInfo.PATH_INVALID) {
+ // Don't notify listeners of devices that haven't reported their physical address yet
+ return;
+ }
invokeDeviceEventListener(info,
HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
}
@@ -489,6 +501,34 @@ public class HdmiCecNetwork {
}
/**
+ * Attempts to deduce the device type of a device given its logical address.
+ * If multiple types are possible, returns {@link HdmiDeviceInfo#DEVICE_RESERVED}.
+ */
+ private static int logicalAddressToDeviceType(int logicalAddress) {
+ switch (logicalAddress) {
+ case Constants.ADDR_TV:
+ return HdmiDeviceInfo.DEVICE_TV;
+ case Constants.ADDR_RECORDER_1:
+ case Constants.ADDR_RECORDER_2:
+ case Constants.ADDR_RECORDER_3:
+ return HdmiDeviceInfo.DEVICE_RECORDER;
+ case Constants.ADDR_TUNER_1:
+ case Constants.ADDR_TUNER_2:
+ case Constants.ADDR_TUNER_3:
+ case Constants.ADDR_TUNER_4:
+ return HdmiDeviceInfo.DEVICE_TUNER;
+ case Constants.ADDR_PLAYBACK_1:
+ case Constants.ADDR_PLAYBACK_2:
+ case Constants.ADDR_PLAYBACK_3:
+ return HdmiDeviceInfo.DEVICE_PLAYBACK;
+ case Constants.ADDR_AUDIO_SYSTEM:
+ return HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM;
+ default:
+ return HdmiDeviceInfo.DEVICE_RESERVED;
+ }
+ }
+
+ /**
* Passively listen to incoming CEC messages.
*
* This shall not result in any CEC messages being sent.
@@ -502,6 +542,7 @@ public class HdmiCecNetwork {
HdmiDeviceInfo newDevice = HdmiDeviceInfo.cecDeviceBuilder()
.setLogicalAddress(sourceAddress)
.setDisplayName(HdmiUtils.getDefaultDeviceName(sourceAddress))
+ .setDeviceType(logicalAddressToDeviceType(sourceAddress))
.build();
addCecDevice(newDevice);
}
@@ -699,7 +740,7 @@ public class HdmiCecNetwork {
return mCecSwitches;
}
- void removeDevicesConnectedToPort(int portId) {
+ void removeCecSwitches(int portId) {
Iterator<Integer> it = mCecSwitches.iterator();
while (it.hasNext()) {
int path = it.next();
@@ -708,6 +749,11 @@ public class HdmiCecNetwork {
it.remove();
}
}
+ }
+
+ void removeDevicesConnectedToPort(int portId) {
+ removeCecSwitches(portId);
+
List<Integer> toRemove = new ArrayList<>();
for (int i = 0; i < mDeviceInfos.size(); i++) {
int key = mDeviceInfos.keyAt(i);
@@ -816,7 +862,10 @@ public class HdmiCecNetwork {
public void clearDeviceList() {
assertRunOnServiceThread();
for (HdmiDeviceInfo info : HdmiUtils.sparseArrayToList(mDeviceInfos)) {
- if (info.getPhysicalAddress() == getPhysicalAddress()) {
+ if (info.getPhysicalAddress() == getPhysicalAddress()
+ || info.getPhysicalAddress() == HdmiDeviceInfo.PATH_INVALID) {
+ // Don't notify listeners of local devices or devices that haven't reported their
+ // physical address yet
continue;
}
invokeDeviceEventListener(info,
@@ -863,10 +912,13 @@ public class HdmiCecNetwork {
* on the current device.
*/
int physicalAddressToPortId(int path) {
+ int physicalAddress = getPhysicalAddress();
+ if (path == physicalAddress) {
+ // The local device isn't connected to any port; assign portId 0
+ return Constants.CEC_SWITCH_HOME;
+ }
int mask = 0xF000;
int finalMask = 0xF000;
- int physicalAddress;
- physicalAddress = getPhysicalAddress();
int maskedAddress = physicalAddress;
while (maskedAddress != 0) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 8ac233114b48..12380abd0d38 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1363,10 +1363,6 @@ public class HdmiControlService extends SystemService {
device.onHotplug(portId, connected);
}
- if (!connected) {
- mHdmiCecNetwork.removeDevicesConnectedToPort(portId);
- }
-
announceHotplugEvent(portId, connected);
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index d2d80ffde532..0de523c5f3f6 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -427,7 +427,7 @@ final class InputMethodBindingController {
addFreshWindowToken();
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
- null, null, null, mCurId, mCurSeq, false);
+ null, null, null, mCurId, mCurSeq, null, false);
}
Slog.w(InputMethodManagerService.TAG,
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1e037ab11031..3c3140551bc3 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -88,6 +88,8 @@ import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
+import android.graphics.Matrix;
+import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputManagerInternal;
import android.inputmethodservice.InputMethodService;
import android.media.AudioManagerInternal;
@@ -124,6 +126,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
+import android.view.DisplayInfo;
import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.View;
@@ -298,6 +301,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
final PackageManagerInternal mPackageManagerInternal;
final InputManagerInternal mInputManagerInternal;
final ImePlatformCompatUtils mImePlatformCompatUtils;
+ private final DisplayManagerInternal mDisplayManagerInternal;
final boolean mHasFeature;
private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
new ArrayMap<>();
@@ -465,6 +469,35 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@GuardedBy("ImfLock.class")
final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
+ private static final class VirtualDisplayInfo {
+ /**
+ * {@link ClientState} where {@link android.hardware.display.VirtualDisplay} is running.
+ */
+ private final ClientState mParentClient;
+ /**
+ * {@link Matrix} to convert screen coordinates in the embedded virtual display to
+ * screen coordinates where {@link #mParentClient} exists.
+ */
+ private final Matrix mMatrix;
+
+ VirtualDisplayInfo(ClientState parentClient, Matrix matrix) {
+ mParentClient = parentClient;
+ mMatrix = matrix;
+ }
+ }
+
+ /**
+ * A mapping table from virtual display IDs created for
+ * {@link android.hardware.display.VirtualDisplay} to its parent IME client where the embedded
+ * virtual display is running.
+ *
+ * <p>Note: this can be used only for virtual display IDs created by
+ * {@link android.hardware.display.VirtualDisplay}.</p>
+ */
+ @GuardedBy("ImfLock.class")
+ private final SparseArray<VirtualDisplayInfo> mVirtualDisplayIdToParentMap =
+ new SparseArray<>();
+
/**
* Set once the system is ready to run third party code.
*/
@@ -562,6 +595,16 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
EditorInfo mCurAttribute;
/**
+ * A special {@link Matrix} to convert virtual screen coordinates to the IME target display
+ * coordinates.
+ *
+ * <p>Used only while the IME client is running in a virtual display. {@code null}
+ * otherwise.</p>
+ */
+ @Nullable
+ private Matrix mCurVirtualDisplayToScreenMatrix = null;
+
+ /**
* Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
* connected to or in the process of connecting to.
*
@@ -1660,6 +1703,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
mImePlatformCompatUtils = new ImePlatformCompatUtils();
mImeDisplayValidator = mWindowManagerInternal::getDisplayImePolicy;
+ mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mUserManager = mContext.getSystemService(UserManager.class);
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
@@ -2333,6 +2377,15 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
clearClientSessionLocked(cs);
clearClientSessionForAccessibilityLocked(cs);
+
+ final int numItems = mVirtualDisplayIdToParentMap.size();
+ for (int i = numItems - 1; i >= 0; --i) {
+ final VirtualDisplayInfo info = mVirtualDisplayIdToParentMap.valueAt(i);
+ if (info.mParentClient == cs) {
+ mVirtualDisplayIdToParentMap.removeAt(i);
+ }
+ }
+
if (mCurClient == cs) {
hideCurrentInputLocked(
mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
@@ -2348,6 +2401,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
mBoundToAccessibility = false;
mCurClient = null;
+ mCurVirtualDisplayToScreenMatrix = null;
}
if (mCurFocusedWindowClient == cs) {
mCurFocusedWindowClient = null;
@@ -2432,6 +2486,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mCurClient.sessionRequested = false;
mCurClient.mSessionRequestedForAccessibility = false;
mCurClient = null;
+ mCurVirtualDisplayToScreenMatrix = null;
mMenuController.hideInputMethodMenuLocked();
}
@@ -2517,7 +2572,33 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
session.session, accessibilityInputMethodSessions,
(session.channel != null ? session.channel.dup() : null),
- curId, getSequenceNumberLocked(), suppressesSpellChecker);
+ curId, getSequenceNumberLocked(), mCurVirtualDisplayToScreenMatrix,
+ suppressesSpellChecker);
+ }
+
+ @GuardedBy("ImfLock.class")
+ @Nullable
+ private Matrix getVirtualDisplayToScreenMatrixLocked(int clientDisplayId, int imeDisplayId) {
+ if (clientDisplayId == imeDisplayId) {
+ return null;
+ }
+ int displayId = clientDisplayId;
+ Matrix matrix = null;
+ while (true) {
+ final VirtualDisplayInfo info = mVirtualDisplayIdToParentMap.get(displayId);
+ if (info == null) {
+ return null;
+ }
+ if (matrix == null) {
+ matrix = new Matrix(info.mMatrix);
+ } else {
+ matrix.postConcat(info.mMatrix);
+ }
+ if (info.mParentClient.selfReportedDisplayId == imeDisplayId) {
+ return matrix;
+ }
+ displayId = info.mParentClient.selfReportedDisplayId;
+ }
}
@GuardedBy("ImfLock.class")
@@ -2551,7 +2632,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WITH_ACCESSIBILITY_SESSION,
imeSession, accessibilityInputMethodSessions, null,
- getCurIdLocked(), getSequenceNumberLocked(), false);
+ getCurIdLocked(), getSequenceNumberLocked(), mCurVirtualDisplayToScreenMatrix,
+ false);
}
return null;
}
@@ -2594,7 +2676,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
// party code.
return new InputBindResult(
InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
- null, null, null, selectedMethodId, getSequenceNumberLocked(), false);
+ null, null, null, selectedMethodId, getSequenceNumberLocked(), null, false);
}
if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
@@ -2625,6 +2707,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
advanceSequenceNumberLocked();
mCurClient = cs;
mCurInputContext = inputContext;
+ mCurVirtualDisplayToScreenMatrix =
+ getVirtualDisplayToScreenMatrixLocked(cs.selfReportedDisplayId,
+ mDisplayIdToShowIme);
mCurAttribute = attribute;
// If configured, we want to avoid starting up the IME if it is not supposed to be showing
@@ -2728,7 +2813,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
requestClientSessionForAccessibilityLocked(cs);
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
- null, null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
+ null, null, null, getCurIdLocked(), getSequenceNumberLocked(), null, false);
} else {
long bindingDuration = SystemClock.uptimeMillis() - getLastBindTimeLocked();
if (bindingDuration < TIME_TO_RECONNECT) {
@@ -2741,7 +2826,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
// to see if we can get back in touch with the service.
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
- null, null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
+ null, null, null, getCurIdLocked(), getSequenceNumberLocked(), null,
+ false);
} else {
EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
getSelectedMethodIdLocked(), bindingDuration, 0);
@@ -3794,7 +3880,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
- null, null, null, null, -1, false);
+ null, null, null, null, -1, null, false);
}
mCurFocusedWindow = windowToken;
@@ -4314,6 +4400,104 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
@Override
+ public void reportVirtualDisplayGeometryAsync(IInputMethodClient parentClient,
+ int childDisplayId, float[] matrixValues) {
+ try {
+ final DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(childDisplayId);
+ if (displayInfo == null) {
+ throw new IllegalArgumentException(
+ "Cannot find display for non-existent displayId: " + childDisplayId);
+ }
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != displayInfo.ownerUid) {
+ throw new SecurityException("The caller doesn't own the display.");
+ }
+
+ synchronized (ImfLock.class) {
+ final ClientState cs = mClients.get(parentClient.asBinder());
+ if (cs == null) {
+ return;
+ }
+
+ // null matrixValues means that the entry needs to be removed.
+ if (matrixValues == null) {
+ final VirtualDisplayInfo info =
+ mVirtualDisplayIdToParentMap.get(childDisplayId);
+ if (info == null) {
+ return;
+ }
+ if (info.mParentClient != cs) {
+ throw new SecurityException("Only the owner client can clear"
+ + " VirtualDisplayGeometry for display #" + childDisplayId);
+ }
+ mVirtualDisplayIdToParentMap.remove(childDisplayId);
+ return;
+ }
+
+ VirtualDisplayInfo info = mVirtualDisplayIdToParentMap.get(childDisplayId);
+ if (info != null && info.mParentClient != cs) {
+ throw new InvalidParameterException("Display #" + childDisplayId
+ + " is already registered by " + info.mParentClient);
+ }
+ if (info == null) {
+ if (!mWindowManagerInternal.isUidAllowedOnDisplay(childDisplayId, cs.uid)) {
+ throw new SecurityException(cs + " cannot access to display #"
+ + childDisplayId);
+ }
+ info = new VirtualDisplayInfo(cs, new Matrix());
+ mVirtualDisplayIdToParentMap.put(childDisplayId, info);
+ }
+ info.mMatrix.setValues(matrixValues);
+
+ if (mCurClient == null || mCurClient.curSession == null) {
+ return;
+ }
+
+ Matrix matrix = null;
+ int displayId = mCurClient.selfReportedDisplayId;
+ boolean needToNotify = false;
+ while (true) {
+ needToNotify |= (displayId == childDisplayId);
+ final VirtualDisplayInfo next = mVirtualDisplayIdToParentMap.get(displayId);
+ if (next == null) {
+ break;
+ }
+ if (matrix == null) {
+ matrix = new Matrix(next.mMatrix);
+ } else {
+ matrix.postConcat(next.mMatrix);
+ }
+ if (next.mParentClient.selfReportedDisplayId == mCurTokenDisplayId) {
+ if (needToNotify) {
+ final float[] values = new float[9];
+ matrix.getValues(values);
+ try {
+ mCurClient.client.updateVirtualDisplayToScreenMatrix(
+ getSequenceNumberLocked(), values);
+ } catch (RemoteException e) {
+ Slog.e(TAG,
+ "Exception calling updateVirtualDisplayToScreenMatrix()",
+ e);
+
+ }
+ }
+ break;
+ }
+ displayId = info.mParentClient.selfReportedDisplayId;
+ }
+ }
+ } catch (Throwable t) {
+ if (parentClient != null) {
+ try {
+ parentClient.throwExceptionFromSystem(t.toString());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception calling throwExceptionFromSystem()", e);
+ }
+ }
+ }
+ }
+
+ @Override
public void removeImeSurfaceFromWindowAsync(IBinder windowToken) {
// No permission check, because we'll only execute the request if the calling window is
// also the current IME client.
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 8407a117be94..bd0e172064c0 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -156,9 +156,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private static final int AGPS_SUPL_MODE_MSA = 0x02;
private static final int AGPS_SUPL_MODE_MSB = 0x01;
- // PSDS stands for Predicted Satellite Data Service
- private static final int DOWNLOAD_PSDS_DATA = 6;
-
// TCP/IP constants.
// Valid TCP/UDP port range is (0, 65535].
private static final int TCP_MIN_PORT = 0;
@@ -286,6 +283,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
// true if PSDS is supported
private boolean mSupportsPsds;
+ private final Object mPsdsPeriodicDownloadToken = new Object();
@GuardedBy("mLock")
private final PowerManager.WakeLock mDownloadPsdsWakeLock;
@GuardedBy("mLock")
@@ -662,6 +660,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
byte[] data = psdsDownloader.downloadPsdsData(psdsType);
if (data != null) {
mHandler.post(() -> {
+ FrameworkStatsLog.write(FrameworkStatsLog.GNSS_PSDS_DOWNLOAD_REPORTED,
+ psdsType);
if (DEBUG) Log.d(TAG, "calling native_inject_psds_data");
mGnssNative.injectPsdsData(data, data.length, psdsType);
synchronized (mLock) {
@@ -670,10 +670,12 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
});
PackageManager pm = mContext.getPackageManager();
if (pm != null && pm.hasSystemFeature(FEATURE_WATCH)
+ && psdsType == GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX
&& mGnssConfiguration.isPsdsPeriodicDownloadEnabled()) {
- if (DEBUG) Log.d(TAG, "scheduling next Psds download");
- mHandler.removeMessages(DOWNLOAD_PSDS_DATA);
- mHandler.sendEmptyMessageDelayed(DOWNLOAD_PSDS_DATA,
+ if (DEBUG) Log.d(TAG, "scheduling next long term Psds download");
+ mHandler.removeCallbacksAndMessages(mPsdsPeriodicDownloadToken);
+ mHandler.postDelayed(() -> handleDownloadPsdsData(psdsType),
+ mPsdsPeriodicDownloadToken,
GnssPsdsDownloader.PSDS_INTERVAL);
}
} else {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index b9238902f44b..78cffa6f4f79 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -635,7 +635,7 @@ public class LockSettingsService extends ILockSettings.Stub {
* If the account is credential-encrypted, show notification requesting the user to unlock the
* device.
*/
- private void maybeShowEncryptionNotificationForUser(@UserIdInt int userId) {
+ private void maybeShowEncryptionNotificationForUser(@UserIdInt int userId, String reason) {
final UserInfo user = mUserManager.getUserInfo(userId);
if (!user.isManagedProfile()) {
// When the user is locked, we communicate it loud-and-clear
@@ -659,28 +659,35 @@ public class LockSettingsService extends ILockSettings.Stub {
!mUserManager.isQuietModeEnabled(userHandle)) {
// Only show notifications for managed profiles once their parent
// user is unlocked.
- showEncryptionNotificationForProfile(userHandle);
+ showEncryptionNotificationForProfile(userHandle, reason);
}
}
}
- private void showEncryptionNotificationForProfile(UserHandle user) {
+ private void showEncryptionNotificationForProfile(UserHandle user, String reason) {
Resources r = mContext.getResources();
CharSequence title = getEncryptionNotificationTitle();
CharSequence message = getEncryptionNotificationMessage();
CharSequence detail = getEncryptionNotificationDetail();
final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
- final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null,
- user.getIdentifier());
+ final Intent unlockIntent =
+ km.createConfirmDeviceCredentialIntent(null, null, user.getIdentifier());
if (unlockIntent == null) {
return;
}
+
+ // Suppress all notifications on non-FBE devices for now
+ if (!StorageManager.isFileEncryptedNativeOrEmulated()) return;
+
unlockIntent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ Slog.d(TAG, String.format("showing encryption notification, user: %d; reason: %s",
+ user.getIdentifier(), reason));
+
showEncryptionNotification(user, title, message, detail, intent);
}
@@ -704,11 +711,6 @@ public class LockSettingsService extends ILockSettings.Stub {
private void showEncryptionNotification(UserHandle user, CharSequence title,
CharSequence message, CharSequence detail, PendingIntent intent) {
- if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
-
- // Suppress all notifications on non-FBE devices for now
- if (!StorageManager.isFileEncryptedNativeOrEmulated()) return;
-
Notification notification =
new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
.setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
@@ -728,7 +730,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
private void hideEncryptionNotification(UserHandle userHandle) {
- if (DEBUG) Slog.v(TAG, "hide encryption notification, user: " + userHandle.getIdentifier());
+ Slog.d(TAG, "hide encryption notification, user: " + userHandle.getIdentifier());
mNotificationManager.cancelAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION,
userHandle);
}
@@ -746,7 +748,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
public void onStartUser(final int userId) {
- maybeShowEncryptionNotificationForUser(userId);
+ maybeShowEncryptionNotificationForUser(userId, "user started");
}
/**
@@ -1497,7 +1499,7 @@ public class LockSettingsService extends ILockSettings.Stub {
if (!alreadyUnlocked) {
final long ident = clearCallingIdentity();
try {
- maybeShowEncryptionNotificationForUser(profile.id);
+ maybeShowEncryptionNotificationForUser(profile.id, "parent unlocked");
} finally {
restoreCallingIdentity(ident);
}
@@ -3316,6 +3318,10 @@ public class LockSettingsService extends ILockSettings.Stub {
if (!mSpManager.hasEscrowData(userId)) {
throw new SecurityException("Escrow token is disabled on the current user");
}
+ if (!isEscrowTokenActive(tokenHandle, userId)) {
+ Slog.e(TAG, "Unknown or unactivated token: " + Long.toHexString(tokenHandle));
+ return false;
+ }
result = setLockCredentialWithTokenInternalLocked(
credential, tokenHandle, token, userId);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 953b6aed9a82..74b11daf6c74 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -423,6 +423,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final int MSG_SET_NETWORK_TEMPLATE_ENABLED = 18;
private static final int MSG_SUBSCRIPTION_PLANS_CHANGED = 19;
private static final int MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED = 20;
+
// TODO: Add similar docs for other messages.
/**
* Message to indicate that reasons for why an uid is blocked changed.
@@ -430,7 +431,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* arg2 = newBlockedReasons
* obj = oldBlockedReasons
*/
- private static final int MSG_BLOCKED_REASON_CHANGED = 21;
+ private static final int MSG_UID_BLOCKED_REASON_CHANGED = 21;
+
/**
* Message to indicate that subscription plans expired and should be cleared.
* arg1 = subId
@@ -439,6 +441,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
*/
private static final int MSG_CLEAR_SUBSCRIPTION_PLANS = 22;
+ /**
+ * Message to indicate that reasons for why some uids are blocked changed.
+ * obj = SparseArray<SomeArgs> where key = uid and value = SomeArgs object with
+ * value.argi1 = oldEffectiveBlockedReasons,
+ * value.argi2 = newEffectiveBlockedReasons,
+ * value.argi3 = uidRules
+ */
+ private static final int MSG_UIDS_BLOCKED_REASONS_CHANGED = 23;
+
private static final int UID_MSG_STATE_CHANGED = 100;
private static final int UID_MSG_GONE = 101;
@@ -476,7 +487,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final Object mUidRulesFirstLock = new Object();
final Object mNetworkPoliciesSecondLock = new Object();
- @GuardedBy({"mUidRulesFirstLock", "mNetworkPoliciesSecondLock"})
+ @GuardedBy(anyOf = {"mUidRulesFirstLock", "mNetworkPoliciesSecondLock"})
volatile boolean mSystemReady;
@GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictBackground;
@@ -1128,6 +1139,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@Override public void onUidCachedChanged(int uid, boolean cached) {
}
+
+ @Override public void onUidProcAdjChanged(int uid) {
+ }
};
private static final class UidStateCallbackInfo {
@@ -3285,7 +3299,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (mSystemReady) {
// Device idle change means we need to rebuild rules for all
// known apps, so do a global refresh.
- updateRulesForRestrictPowerUL();
+ handleDeviceIdleModeChangedUL(enabled);
}
}
if (enabled) {
@@ -4511,6 +4525,68 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ @GuardedBy("mUidRulesFirstLock")
+ private void handleDeviceIdleModeChangedUL(boolean enabled) {
+ Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL");
+ try {
+ updateRulesForDeviceIdleUL();
+ if (enabled) {
+ forEachUid("updateRulesForRestrictPower", uid -> {
+ synchronized (mUidRulesFirstLock) {
+ updateRulesForPowerRestrictionsUL(uid);
+ }
+ });
+ } else {
+ // TODO: Note that we could handle the case of enabling-doze state similar
+ // to this but first, we need to update how we listen to uid state changes
+ // so that we always get a callback when a process moves from a NONEXISTENT state
+ // to a "background" state.
+ handleDeviceIdleModeDisabledUL();
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
+ }
+ }
+
+ @GuardedBy("mUidRulesFirstLock")
+ private void handleDeviceIdleModeDisabledUL() {
+ Trace.traceBegin(TRACE_TAG_NETWORK, "handleDeviceIdleModeDisabledUL");
+ try {
+ final SparseArray<SomeArgs> uidStateUpdates = new SparseArray<>();
+ synchronized (mUidBlockedState) {
+ final int size = mUidBlockedState.size();
+ for (int i = 0; i < size; ++i) {
+ final int uid = mUidBlockedState.keyAt(i);
+ final UidBlockedState uidBlockedState = mUidBlockedState.valueAt(i);
+ if ((uidBlockedState.blockedReasons & BLOCKED_REASON_DOZE) == 0) {
+ continue;
+ }
+ uidBlockedState.blockedReasons &= ~BLOCKED_REASON_DOZE;
+ final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ uidBlockedState.updateEffectiveBlockedReasons();
+ if (LOGV) {
+ Log.v(TAG, "handleDeviceIdleModeDisabled(" + uid + "); "
+ + "newUidBlockedState=" + uidBlockedState
+ + ", oldEffectiveBlockedReasons=" + oldEffectiveBlockedReasons);
+ }
+ if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
+ final SomeArgs someArgs = SomeArgs.obtain();
+ someArgs.argi1 = oldEffectiveBlockedReasons;
+ someArgs.argi2 = uidBlockedState.effectiveBlockedReasons;
+ someArgs.argi3 = uidBlockedState.deriveUidRules();
+ uidStateUpdates.append(uid, someArgs);
+ }
+ }
+ }
+ if (uidStateUpdates.size() != 0) {
+ mHandler.obtainMessage(MSG_UIDS_BLOCKED_REASONS_CHANGED, uidStateUpdates)
+ .sendToTarget();
+ }
+ } finally {
+ Trace.traceEnd(TRACE_TAG_NETWORK);
+ }
+ }
+
// TODO: rename / document to make it clear these are global (not app-specific) rules
@GuardedBy("mUidRulesFirstLock")
private void updateRulesForRestrictPowerUL() {
@@ -5027,8 +5103,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) {
postBlockedReasonsChangedMsg(uid,
- oldEffectiveBlockedReasons,
- newEffectiveBlockedReasons);
+ newEffectiveBlockedReasons,
+ oldEffectiveBlockedReasons);
postUidRulesChangedMsg(uid, uidRules);
}
@@ -5061,7 +5137,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private void postBlockedReasonsChangedMsg(int uid, int newEffectiveBlockedReasons,
int oldEffectiveBlockedReasons) {
- mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
+ mHandler.obtainMessage(MSG_UID_BLOCKED_REASON_CHANGED, uid,
newEffectiveBlockedReasons, oldEffectiveBlockedReasons)
.sendToTarget();
}
@@ -5308,7 +5384,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
return true;
}
- case MSG_BLOCKED_REASON_CHANGED: {
+ case MSG_UID_BLOCKED_REASON_CHANGED: {
final int uid = msg.arg1;
final int newBlockedReasons = msg.arg2;
final int oldBlockedReasons = (int) msg.obj;
@@ -5321,6 +5397,35 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mListeners.finishBroadcast();
return true;
}
+ case MSG_UIDS_BLOCKED_REASONS_CHANGED: {
+ final SparseArray<SomeArgs> uidStateUpdates = (SparseArray<SomeArgs>) msg.obj;
+ final int uidsSize = uidStateUpdates.size();
+ final int listenersSize = mListeners.beginBroadcast();
+ for (int i = 0; i < listenersSize; ++i) {
+ final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
+ for (int uidIndex = 0; uidIndex < uidsSize; ++uidIndex) {
+ final int uid = uidStateUpdates.keyAt(uidIndex);
+ final SomeArgs someArgs = uidStateUpdates.valueAt(uidIndex);
+ final int oldBlockedReasons = someArgs.argi1;
+ final int newBlockedReasons = someArgs.argi2;
+ final int uidRules = someArgs.argi3;
+
+ dispatchBlockedReasonChanged(listener, uid,
+ oldBlockedReasons, newBlockedReasons);
+ if (LOGV) {
+ Slog.v(TAG, "Dispatching rules=" + uidRulesToString(uidRules)
+ + " for uid=" + uid);
+ }
+ dispatchUidRulesChanged(listener, uid, uidRules);
+ }
+ }
+ mListeners.finishBroadcast();
+
+ for (int uidIndex = 0; uidIndex < uidsSize; ++uidIndex) {
+ uidStateUpdates.valueAt(uidIndex).recycle();
+ }
+ return true;
+ }
default: {
return false;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 326a5f2582e1..9af5b667fc44 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -264,7 +264,6 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index ee0b3d52eb3d..8ecc607603a1 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -82,6 +82,7 @@ import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
+import com.android.server.pm.KnownPackages;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -1264,7 +1265,7 @@ public final class OverlayManagerService extends SystemService {
@Override
public String getConfigSignaturePackage() {
final String[] pkgs = mPackageManagerInternal.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE,
+ KnownPackages.PACKAGE_OVERLAY_CONFIG_SIGNATURE,
UserHandle.USER_SYSTEM);
return (pkgs.length == 0) ? null : pkgs[0];
}
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilterImpl.java
index 152c74553d32..17dc403cf2c5 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilterImpl.java
@@ -44,7 +44,6 @@ import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.util.SparseSetArray;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -52,7 +51,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.function.QuadFunction;
import com.android.server.FgThread;
-import com.android.server.LocalServices;
import com.android.server.compat.CompatChange;
import com.android.server.om.OverlayReferenceMapper;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -65,14 +63,18 @@ import com.android.server.pm.pkg.component.ParsedMainComponent;
import com.android.server.pm.pkg.component.ParsedProvider;
import com.android.server.utils.Snappable;
import com.android.server.utils.SnapshotCache;
-import com.android.server.utils.Snapshots;
import com.android.server.utils.Watchable;
import com.android.server.utils.WatchableImpl;
+import com.android.server.utils.Watched;
+import com.android.server.utils.WatchedArrayList;
import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.WatchedArraySet;
import com.android.server.utils.WatchedSparseBooleanMatrix;
+import com.android.server.utils.WatchedSparseSetArray;
import com.android.server.utils.Watcher;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -85,7 +87,7 @@ import java.util.concurrent.Executor;
* manifests.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public class AppsFilter implements Watchable, Snappable {
+public class AppsFilterImpl implements AppsFilterSnapshot, Watchable, Snappable {
private static final String TAG = "AppsFilter";
@@ -100,32 +102,48 @@ public class AppsFilter implements Watchable, Snappable {
* application B is implicitly allowed to query for application A; regardless of any manifest
* entries.
*/
- private final SparseSetArray<Integer> mImplicitlyQueryable = new SparseSetArray<>();
+ @GuardedBy("mLock")
+ @Watched
+ private final WatchedSparseSetArray<Integer> mImplicitlyQueryable;
+ private final SnapshotCache<WatchedSparseSetArray<Integer>> mImplicitQueryableSnapshot;
/**
* This contains a list of app UIDs that are implicitly queryable because another app explicitly
* interacted with it, but could keep across package updates. For example, if application A
* grants persistable uri permission to application B; regardless of any manifest entries.
*/
- private final SparseSetArray<Integer> mRetainedImplicitlyQueryable = new SparseSetArray<>();
+ @GuardedBy("mLock")
+ @Watched
+ private final WatchedSparseSetArray<Integer> mRetainedImplicitlyQueryable;
+ private final SnapshotCache<WatchedSparseSetArray<Integer>>
+ mRetainedImplicitlyQueryableSnapshot;
/**
* A mapping from the set of App IDs that query other App IDs via package name to the
* list of packages that they can see.
*/
- private final SparseSetArray<Integer> mQueriesViaPackage = new SparseSetArray<>();
+ @GuardedBy("mLock")
+ @Watched
+ private final WatchedSparseSetArray<Integer> mQueriesViaPackage;
+ private final SnapshotCache<WatchedSparseSetArray<Integer>> mQueriesViaPackageSnapshot;
/**
* A mapping from the set of App IDs that query others via component match to the list
* of packages that the they resolve to.
*/
- private final SparseSetArray<Integer> mQueriesViaComponent = new SparseSetArray<>();
+ @GuardedBy("mLock")
+ @Watched
+ private final WatchedSparseSetArray<Integer> mQueriesViaComponent;
+ private final SnapshotCache<WatchedSparseSetArray<Integer>> mQueriesViaComponentSnapshot;
/**
* A mapping from the set of App IDs that query other App IDs via library name to the
* list of packages that they can see.
*/
- private final SparseSetArray<Integer> mQueryableViaUsesLibrary = new SparseSetArray<>();
+ @GuardedBy("mLock")
+ @Watched
+ private final WatchedSparseSetArray<Integer> mQueryableViaUsesLibrary;
+ private final SnapshotCache<WatchedSparseSetArray<Integer>> mQueryableViaUsesLibrarySnapshot;
/**
* Executor for running reasonably short background tasks such as building the initial
@@ -145,7 +163,10 @@ public class AppsFilter implements Watchable, Snappable {
* A set of App IDs that are always queryable by any package, regardless of their manifest
* content.
*/
- private final ArraySet<Integer> mForceQueryable = new ArraySet<>();
+ @Watched
+ @GuardedBy("mLock")
+ private final WatchedArraySet<Integer> mForceQueryable;
+ private final SnapshotCache<WatchedArraySet<Integer>> mForceQueryableSnapshot;
/**
* The set of package names provided by the device that should be force queryable regardless of
@@ -155,14 +176,16 @@ public class AppsFilter implements Watchable, Snappable {
/** True if all system apps should be made queryable by default. */
private final boolean mSystemAppsQueryable;
-
private final FeatureConfig mFeatureConfig;
private final OverlayReferenceMapper mOverlayReferenceMapper;
private final StateProvider mStateProvider;
private final PackageManagerInternal mPmInternal;
-
private SigningDetails mSystemSigningDetails;
- private Set<String> mProtectedBroadcasts = new ArraySet<>();
+
+ @GuardedBy("mLock")
+ @Watched
+ private final WatchedArrayList<String> mProtectedBroadcasts;
+ private final SnapshotCache<WatchedArrayList<String>> mProtectedBroadcastsSnapshot;
private final Object mCacheLock = new Object();
@@ -171,29 +194,47 @@ public class AppsFilter implements Watchable, Snappable {
* filtered to the second. It's essentially a cache of the
* {@link #shouldFilterApplicationInternal(int, Object, PackageStateInternal, int)} call.
* NOTE: It can only be relied upon after the system is ready to avoid unnecessary update on
- * initial scam and is null until {@link #onSystemReady()} is called.
+ * initial scam and is empty until {@link #onSystemReady()} is called.
*/
@GuardedBy("mCacheLock")
- private volatile WatchedSparseBooleanMatrix mShouldFilterCache;
+ @NonNull
+ private final WatchedSparseBooleanMatrix mShouldFilterCache;
+ private final SnapshotCache<WatchedSparseBooleanMatrix> mShouldFilterCacheSnapshot;
+
+ /**
+ * Guards the accesses for the list/set fields except for {@link #mShouldFilterCache}
+ */
+ private final Object mLock = new Object();
/**
* A cached snapshot.
*/
- private final SnapshotCache<AppsFilter> mSnapshot;
+ private final SnapshotCache<AppsFilterImpl> mSnapshot;
- private SnapshotCache<AppsFilter> makeCache() {
- return new SnapshotCache<AppsFilter>(this, this) {
+ private SnapshotCache<AppsFilterImpl> makeCache() {
+ return new SnapshotCache<AppsFilterImpl>(this, this) {
@Override
- public AppsFilter createSnapshot() {
- AppsFilter s = new AppsFilter(mSource);
+ public AppsFilterImpl createSnapshot() {
+ AppsFilterImpl s = new AppsFilterImpl(mSource);
+ s.mWatchable.seal();
return s;
- }};
+ }
+ };
}
/**
* Watchable machinery
*/
private final WatchableImpl mWatchable = new WatchableImpl();
+ /**
+ * The observer that watches for changes from array members
+ */
+ private final Watcher mObserver = new Watcher() {
+ @Override
+ public void onChange(@Nullable Watchable what) {
+ AppsFilterImpl.this.dispatchChange(what);
+ }
+ };
/**
* Ensures an observer is in the list, exactly once. The observer cannot be null. The
@@ -219,6 +260,7 @@ public class AppsFilter implements Watchable, Snappable {
/**
* Return true if the {@link Watcher) is a registered observer.
+ *
* @param observer A {@link Watcher} that might be registered
* @return true if the observer is registered with this {@link Watchable}.
*/
@@ -247,7 +289,7 @@ public class AppsFilter implements Watchable, Snappable {
}
@VisibleForTesting(visibility = PRIVATE)
- AppsFilter(StateProvider stateProvider,
+ AppsFilterImpl(StateProvider stateProvider,
FeatureConfig featureConfig,
String[] forceQueryableList,
boolean systemAppsQueryable,
@@ -262,34 +304,70 @@ public class AppsFilter implements Watchable, Snappable {
mStateProvider = stateProvider;
mPmInternal = pmInternal;
mBackgroundExecutor = backgroundExecutor;
+ mImplicitlyQueryable = new WatchedSparseSetArray<>();
+ mImplicitQueryableSnapshot = new SnapshotCache.Auto<>(
+ mImplicitlyQueryable, mImplicitlyQueryable, "AppsFilter.mImplicitlyQueryable");
+ mRetainedImplicitlyQueryable = new WatchedSparseSetArray<>();
+ mRetainedImplicitlyQueryableSnapshot = new SnapshotCache.Auto<>(
+ mRetainedImplicitlyQueryable, mRetainedImplicitlyQueryable,
+ "AppsFilter.mRetainedImplicitlyQueryable");
+ mQueriesViaPackage = new WatchedSparseSetArray<>();
+ mQueriesViaPackageSnapshot = new SnapshotCache.Auto<>(
+ mQueriesViaPackage, mQueriesViaPackage, "AppsFilter.mQueriesViaPackage");
+ mQueriesViaComponent = new WatchedSparseSetArray<>();
+ mQueriesViaComponentSnapshot = new SnapshotCache.Auto<>(
+ mQueriesViaComponent, mQueriesViaComponent, "AppsFilter.mQueriesViaComponent");
+ mQueryableViaUsesLibrary = new WatchedSparseSetArray<>();
+ mQueryableViaUsesLibrarySnapshot = new SnapshotCache.Auto<>(
+ mQueryableViaUsesLibrary, mQueryableViaUsesLibrary,
+ "AppsFilter.mQueryableViaUsesLibrary");
+ mForceQueryable = new WatchedArraySet<>();
+ mForceQueryableSnapshot = new SnapshotCache.Auto<>(
+ mForceQueryable, mForceQueryable, "AppsFilter.mForceQueryable");
+ mProtectedBroadcasts = new WatchedArrayList<>();
+ mProtectedBroadcastsSnapshot = new SnapshotCache.Auto<>(
+ mProtectedBroadcasts, mProtectedBroadcasts, "AppsFilter.mProtectedBroadcasts");
+ mShouldFilterCache = new WatchedSparseBooleanMatrix();
+ mShouldFilterCacheSnapshot = new SnapshotCache.Auto<>(
+ mShouldFilterCache, mShouldFilterCache, "AppsFilter.mShouldFilterCache");
+
+ registerObservers();
+ Watchable.verifyWatchedAttributes(this, mObserver);
mSnapshot = makeCache();
}
/**
* The copy constructor is used by PackageManagerService to construct a snapshot.
- * Attributes are not deep-copied since these are supposed to be immutable.
- * TODO: deep-copy the attributes, if necessary.
*/
- private AppsFilter(AppsFilter orig) {
- Snapshots.copy(mImplicitlyQueryable, orig.mImplicitlyQueryable);
- Snapshots.copy(mRetainedImplicitlyQueryable, orig.mRetainedImplicitlyQueryable);
- Snapshots.copy(mQueriesViaPackage, orig.mQueriesViaPackage);
- Snapshots.copy(mQueriesViaComponent, orig.mQueriesViaComponent);
- Snapshots.copy(mQueryableViaUsesLibrary, orig.mQueryableViaUsesLibrary);
+ private AppsFilterImpl(AppsFilterImpl orig) {
+ synchronized (orig.mLock) {
+ mImplicitlyQueryable = orig.mImplicitQueryableSnapshot.snapshot();
+ mImplicitQueryableSnapshot = new SnapshotCache.Sealed<>();
+ mRetainedImplicitlyQueryable = orig.mRetainedImplicitlyQueryableSnapshot.snapshot();
+ mRetainedImplicitlyQueryableSnapshot = new SnapshotCache.Sealed<>();
+ mQueriesViaPackage = orig.mQueriesViaPackageSnapshot.snapshot();
+ mQueriesViaPackageSnapshot = new SnapshotCache.Sealed<>();
+ mQueriesViaComponent = orig.mQueriesViaComponentSnapshot.snapshot();
+ mQueriesViaComponentSnapshot = new SnapshotCache.Sealed<>();
+ mQueryableViaUsesLibrary = orig.mQueryableViaUsesLibrarySnapshot.snapshot();
+ mQueryableViaUsesLibrarySnapshot = new SnapshotCache.Sealed<>();
+ mForceQueryable = orig.mForceQueryableSnapshot.snapshot();
+ mForceQueryableSnapshot = new SnapshotCache.Sealed<>();
+ mProtectedBroadcasts = orig.mProtectedBroadcastsSnapshot.snapshot();
+ mProtectedBroadcastsSnapshot = new SnapshotCache.Sealed<>();
+ }
mQueriesViaComponentRequireRecompute = orig.mQueriesViaComponentRequireRecompute;
- mForceQueryable.addAll(orig.mForceQueryable);
- mForceQueryableByDevicePackageNames = orig.mForceQueryableByDevicePackageNames;
+ mForceQueryableByDevicePackageNames =
+ Arrays.copyOf(orig.mForceQueryableByDevicePackageNames,
+ orig.mForceQueryableByDevicePackageNames.length);
mSystemAppsQueryable = orig.mSystemAppsQueryable;
mFeatureConfig = orig.mFeatureConfig;
mOverlayReferenceMapper = orig.mOverlayReferenceMapper;
mStateProvider = orig.mStateProvider;
mSystemSigningDetails = orig.mSystemSigningDetails;
- mProtectedBroadcasts = orig.mProtectedBroadcasts;
- mShouldFilterCache = orig.mShouldFilterCache;
- if (mShouldFilterCache != null) {
- synchronized (orig.mCacheLock) {
- mShouldFilterCache = mShouldFilterCache.snapshot();
- }
+ synchronized (orig.mCacheLock) {
+ mShouldFilterCache = orig.mShouldFilterCacheSnapshot.snapshot();
+ mShouldFilterCacheSnapshot = new SnapshotCache.Sealed<>();
}
mBackgroundExecutor = null;
@@ -297,12 +375,24 @@ public class AppsFilter implements Watchable, Snappable {
mSnapshot = new SnapshotCache.Sealed<>();
}
+ @SuppressWarnings("GuardedBy")
+ private void registerObservers() {
+ mImplicitlyQueryable.registerObserver(mObserver);
+ mRetainedImplicitlyQueryable.registerObserver(mObserver);
+ mQueriesViaPackage.registerObserver(mObserver);
+ mQueriesViaComponent.registerObserver(mObserver);
+ mQueryableViaUsesLibrary.registerObserver(mObserver);
+ mForceQueryable.registerObserver(mObserver);
+ mProtectedBroadcasts.registerObserver(mObserver);
+ mShouldFilterCache.registerObserver(mObserver);
+ }
+
/**
* Return a snapshot. If the cached snapshot is null, build a new one. The logic in
* the function ensures that this function returns a valid snapshot even if a race
* condition causes the cached snapshot to be cleared asynchronously to this method.
*/
- public AppsFilter snapshot() {
+ public AppsFilterSnapshot snapshot() {
return mSnapshot.snapshot();
}
@@ -363,7 +453,7 @@ public class AppsFilter implements Watchable, Snappable {
@Nullable
private SparseBooleanArray mLoggingEnabled = null;
- private AppsFilter mAppsFilter;
+ private AppsFilterImpl mAppsFilter;
private FeatureConfigImpl(
PackageManagerInternal pmInternal, PackageManagerServiceInjector injector) {
@@ -371,7 +461,7 @@ public class AppsFilter implements Watchable, Snappable {
mInjector = injector;
}
- public void setAppsFilter(AppsFilter filter) {
+ public void setAppsFilter(AppsFilterImpl filter) {
mAppsFilter = filter;
}
@@ -475,8 +565,9 @@ public class AppsFilter implements Watchable, Snappable {
@Override
public void updatePackageState(PackageStateInternal setting, boolean removed) {
- final boolean enableLogging = setting.getPkg() != null &&
- !removed && (setting.getPkg().isTestOnly() || setting.getPkg().isDebuggable());
+ final boolean enableLogging = setting.getPkg() != null
+ && !removed && (setting.getPkg().isTestOnly()
+ || setting.getPkg().isDebuggable());
enableLogging(setting.getAppId(), enableLogging);
if (removed) {
mDisabledPackages.remove(setting.getPackageName());
@@ -487,7 +578,7 @@ public class AppsFilter implements Watchable, Snappable {
}
/** Builder method for an AppsFilter */
- public static AppsFilter create(@NonNull PackageManagerServiceInjector injector,
+ public static AppsFilterImpl create(@NonNull PackageManagerServiceInjector injector,
@NonNull PackageManagerInternal pmInt) {
final boolean forceSystemAppsQueryable =
injector.getContext().getResources()
@@ -511,7 +602,7 @@ public class AppsFilter implements Watchable, Snappable {
injector.getUserManagerInternal().getUserInfos());
}
};
- AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig,
+ AppsFilterImpl appsFilter = new AppsFilterImpl(stateProvider, featureConfig,
forcedQueryablePackageNames, forceSystemAppsQueryable, null,
injector.getBackgroundExecutor(), pmInt);
featureConfig.setAppsFilter(appsFilter);
@@ -524,7 +615,7 @@ public class AppsFilter implements Watchable, Snappable {
/** Returns true if the querying package may query for the potential target package */
private static boolean canQueryViaComponents(AndroidPackage querying,
- AndroidPackage potentialTarget, Set<String> protectedBroadcasts) {
+ AndroidPackage potentialTarget, WatchedArrayList<String> protectedBroadcasts) {
if (!querying.getQueriesIntents().isEmpty()) {
for (Intent intent : querying.getQueriesIntents()) {
if (matchesPackage(intent, potentialTarget, protectedBroadcasts)) {
@@ -596,7 +687,7 @@ public class AppsFilter implements Watchable, Snappable {
}
private static boolean matchesPackage(Intent intent, AndroidPackage potentialTarget,
- Set<String> protectedBroadcasts) {
+ WatchedArrayList<String> protectedBroadcasts) {
if (matchesAnyComponents(
intent, potentialTarget.getServices(), null /*protectedBroadcasts*/)) {
return true;
@@ -617,7 +708,7 @@ public class AppsFilter implements Watchable, Snappable {
private static boolean matchesAnyComponents(Intent intent,
List<? extends ParsedMainComponent> components,
- Set<String> protectedBroadcasts) {
+ WatchedArrayList<String> protectedBroadcasts) {
for (int i = ArrayUtils.size(components) - 1; i >= 0; i--) {
ParsedMainComponent component = components.get(i);
if (!component.isExported()) {
@@ -631,7 +722,7 @@ public class AppsFilter implements Watchable, Snappable {
}
private static boolean matchesAnyFilter(Intent intent, ParsedComponent component,
- Set<String> protectedBroadcasts) {
+ WatchedArrayList<String> protectedBroadcasts) {
List<ParsedIntentInfo> intents = component.getIntents();
for (int i = ArrayUtils.size(intents) - 1; i >= 0; i--) {
IntentFilter intentFilter = intents.get(i).getIntentFilter();
@@ -643,38 +734,38 @@ public class AppsFilter implements Watchable, Snappable {
}
private static boolean matchesIntentFilter(Intent intent, IntentFilter intentFilter,
- @Nullable Set<String> protectedBroadcasts) {
+ @Nullable WatchedArrayList<String> protectedBroadcasts) {
return intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(),
- intent.getData(), intent.getCategories(), "AppsFilter", true, protectedBroadcasts)
- > 0;
+ intent.getData(), intent.getCategories(), "AppsFilter", true,
+ protectedBroadcasts != null ? protectedBroadcasts.untrackedStorage() : null) > 0;
}
/**
* Grants access based on an interaction between a calling and target package, granting
* visibility of the caller from the target.
*
- * @param recipientUid the uid gaining visibility of the {@code visibleUid}.
- * @param visibleUid the uid becoming visible to the {@recipientUid}
- * @param retainOnUpdate if the implicit access retained across package updates.
+ * @param recipientUid the uid gaining visibility of the {@code visibleUid}.
+ * @param visibleUid the uid becoming visible to the {@recipientUid}
+ * @param retainOnUpdate if the implicit access retained across package updates.
* @return {@code true} if implicit access was not already granted.
*/
public boolean grantImplicitAccess(int recipientUid, int visibleUid, boolean retainOnUpdate) {
if (recipientUid == visibleUid) {
return false;
}
- final boolean changed = retainOnUpdate
- ? mRetainedImplicitlyQueryable.add(recipientUid, visibleUid)
- : mImplicitlyQueryable.add(recipientUid, visibleUid);
- if (changed && DEBUG_LOGGING) {
- Slog.i(TAG, (retainOnUpdate ? "retained " : "") + "implicit access granted: "
- + recipientUid + " -> " + visibleUid);
+ final boolean changed;
+ synchronized (mLock) {
+ changed = retainOnUpdate
+ ? mRetainedImplicitlyQueryable.add(recipientUid, visibleUid)
+ : mImplicitlyQueryable.add(recipientUid, visibleUid);
+ if (changed && DEBUG_LOGGING) {
+ Slog.i(TAG, (retainOnUpdate ? "retained " : "") + "implicit access granted: "
+ + recipientUid + " -> " + visibleUid);
+ }
}
synchronized (mCacheLock) {
- if (mShouldFilterCache != null) {
- // update the cache in a one-off manner since we've got all the information we
- // need.
- mShouldFilterCache.put(recipientUid, visibleUid, false);
- }
+ // update the cache in a one-off manner since we've got all the information we need.
+ mShouldFilterCache.put(recipientUid, visibleUid, false);
}
if (changed) {
onChanged();
@@ -694,7 +785,7 @@ public class AppsFilter implements Watchable, Snappable {
* Adds a package that should be considered when filtering visibility between apps.
*
* @param newPkgSetting the new setting being added
- * @param isReplace if the package is being replaced and may need extra cleanup.
+ * @param isReplace if the package is being replaced and may need extra cleanup.
*/
public void addPackage(PackageStateInternal newPkgSetting, boolean isReplace) {
if (DEBUG_TRACING) {
@@ -709,27 +800,25 @@ public class AppsFilter implements Watchable, Snappable {
ArraySet<String> additionalChangedPackages =
addPackageInternal(newPkgSetting, settings);
synchronized (mCacheLock) {
- if (mShouldFilterCache != null) {
- updateShouldFilterCacheForPackage(mShouldFilterCache, null, newPkgSetting,
- settings, users, USER_ALL, settings.size());
- if (additionalChangedPackages != null) {
- for (int index = 0; index < additionalChangedPackages.size(); index++) {
- String changedPackage = additionalChangedPackages.valueAt(index);
- PackageStateInternal changedPkgSetting =
- settings.get(changedPackage);
- if (changedPkgSetting == null) {
- // It's possible for the overlay mapper to know that an actor
- // package changed via an explicit reference, even if the actor
- // isn't installed, so skip if that's the case.
- continue;
- }
-
- updateShouldFilterCacheForPackage(mShouldFilterCache, null,
- changedPkgSetting, settings, users, USER_ALL,
- settings.size());
+ updateShouldFilterCacheForPackage(mShouldFilterCache, null, newPkgSetting,
+ settings, users, USER_ALL, settings.size());
+ if (additionalChangedPackages != null) {
+ for (int index = 0; index < additionalChangedPackages.size(); index++) {
+ String changedPackage = additionalChangedPackages.valueAt(index);
+ PackageStateInternal changedPkgSetting =
+ settings.get(changedPackage);
+ if (changedPkgSetting == null) {
+ // It's possible for the overlay mapper to know that an actor
+ // package changed via an explicit reference, even if the actor
+ // isn't installed, so skip if that's the case.
+ continue;
}
+
+ updateShouldFilterCacheForPackage(mShouldFilterCache, null,
+ changedPkgSetting, settings, users, USER_ALL,
+ settings.size());
}
- } // else, rebuild entire cache when system is ready
+ }
}
});
} finally {
@@ -752,9 +841,11 @@ public class AppsFilter implements Watchable, Snappable {
mSystemSigningDetails = newPkgSetting.getSigningDetails();
// and since we add overlays before we add the framework, let's revisit already added
// packages for signature matches
- for (PackageStateInternal setting : existingSettings.values()) {
- if (isSystemSigned(mSystemSigningDetails, setting)) {
- mForceQueryable.add(setting.getAppId());
+ synchronized (mLock) {
+ for (PackageStateInternal setting : existingSettings.values()) {
+ if (isSystemSigned(mSystemSigningDetails, setting)) {
+ mForceQueryable.add(setting.getAppId());
+ }
}
}
}
@@ -764,67 +855,74 @@ public class AppsFilter implements Watchable, Snappable {
return null;
}
- if (mProtectedBroadcasts.addAll(newPkg.getProtectedBroadcasts())) {
- mQueriesViaComponentRequireRecompute = true;
- }
-
- final boolean newIsForceQueryable =
- mForceQueryable.contains(newPkgSetting.getAppId())
- /* shared user that is already force queryable */
- || newPkgSetting.isForceQueryableOverride() /* adb override */
- || (newPkgSetting.isSystem() && (mSystemAppsQueryable
- || newPkg.isForceQueryable()
- || ArrayUtils.contains(mForceQueryableByDevicePackageNames,
- newPkg.getPackageName())));
- if (newIsForceQueryable
- || (mSystemSigningDetails != null
- && isSystemSigned(mSystemSigningDetails, newPkgSetting))) {
- mForceQueryable.add(newPkgSetting.getAppId());
- }
+ synchronized (mLock) {
+ if (mProtectedBroadcasts.addAll(newPkg.getProtectedBroadcasts())) {
+ mQueriesViaComponentRequireRecompute = true;
+ }
- for (int i = existingSettings.size() - 1; i >= 0; i--) {
- final PackageStateInternal existingSetting = existingSettings.valueAt(i);
- if (existingSetting.getAppId() == newPkgSetting.getAppId() || existingSetting.getPkg()
- == null) {
- continue;
+ final boolean newIsForceQueryable =
+ mForceQueryable.contains(newPkgSetting.getAppId())
+ /* shared user that is already force queryable */
+ || newPkgSetting.isForceQueryableOverride() /* adb override */
+ || (newPkgSetting.isSystem() && (mSystemAppsQueryable
+ || newPkg.isForceQueryable()
+ || ArrayUtils.contains(mForceQueryableByDevicePackageNames,
+ newPkg.getPackageName())));
+ if (newIsForceQueryable
+ || (mSystemSigningDetails != null
+ && isSystemSigned(mSystemSigningDetails, newPkgSetting))) {
+ mForceQueryable.add(newPkgSetting.getAppId());
}
- final AndroidPackage existingPkg = existingSetting.getPkg();
- // let's evaluate the ability of already added packages to see this new package
- if (!newIsForceQueryable) {
- if (!mQueriesViaComponentRequireRecompute && canQueryViaComponents(existingPkg,
- newPkg, mProtectedBroadcasts)) {
- mQueriesViaComponent.add(existingSetting.getAppId(), newPkgSetting.getAppId());
- }
- if (canQueryViaPackage(existingPkg, newPkg)
- || canQueryAsInstaller(existingSetting, newPkg)) {
- mQueriesViaPackage.add(existingSetting.getAppId(), newPkgSetting.getAppId());
+
+ for (int i = existingSettings.size() - 1; i >= 0; i--) {
+ final PackageStateInternal existingSetting = existingSettings.valueAt(i);
+ if (existingSetting.getAppId() == newPkgSetting.getAppId()
+ || existingSetting.getPkg()
+ == null) {
+ continue;
}
- if (canQueryViaUsesLibrary(existingPkg, newPkg)) {
- mQueryableViaUsesLibrary.add(existingSetting.getAppId(),
- newPkgSetting.getAppId());
+ final AndroidPackage existingPkg = existingSetting.getPkg();
+ // let's evaluate the ability of already added packages to see this new package
+ if (!newIsForceQueryable) {
+ if (!mQueriesViaComponentRequireRecompute && canQueryViaComponents(existingPkg,
+ newPkg, mProtectedBroadcasts)) {
+ mQueriesViaComponent.add(existingSetting.getAppId(),
+ newPkgSetting.getAppId());
+ }
+ if (canQueryViaPackage(existingPkg, newPkg)
+ || canQueryAsInstaller(existingSetting, newPkg)) {
+ mQueriesViaPackage.add(existingSetting.getAppId(),
+ newPkgSetting.getAppId());
+ }
+ if (canQueryViaUsesLibrary(existingPkg, newPkg)) {
+ mQueryableViaUsesLibrary.add(existingSetting.getAppId(),
+ newPkgSetting.getAppId());
+ }
}
- }
- // now we'll evaluate our new package's ability to see existing packages
- if (!mForceQueryable.contains(existingSetting.getAppId())) {
- if (!mQueriesViaComponentRequireRecompute && canQueryViaComponents(newPkg,
- existingPkg, mProtectedBroadcasts)) {
- mQueriesViaComponent.add(newPkgSetting.getAppId(), existingSetting.getAppId());
+ // now we'll evaluate our new package's ability to see existing packages
+ if (!mForceQueryable.contains(existingSetting.getAppId())) {
+ if (!mQueriesViaComponentRequireRecompute && canQueryViaComponents(newPkg,
+ existingPkg, mProtectedBroadcasts)) {
+ mQueriesViaComponent.add(newPkgSetting.getAppId(),
+ existingSetting.getAppId());
+ }
+ if (canQueryViaPackage(newPkg, existingPkg)
+ || canQueryAsInstaller(newPkgSetting, existingPkg)) {
+ mQueriesViaPackage.add(newPkgSetting.getAppId(),
+ existingSetting.getAppId());
+ }
+ if (canQueryViaUsesLibrary(newPkg, existingPkg)) {
+ mQueryableViaUsesLibrary.add(newPkgSetting.getAppId(),
+ existingSetting.getAppId());
+ }
}
- if (canQueryViaPackage(newPkg, existingPkg)
- || canQueryAsInstaller(newPkgSetting, existingPkg)) {
+ // if either package instruments the other, mark both as visible to one another
+ if (newPkgSetting.getPkg() != null && existingSetting.getPkg() != null
+ && (pkgInstruments(newPkgSetting.getPkg(), existingSetting.getPkg())
+ || pkgInstruments(existingSetting.getPkg(), newPkgSetting.getPkg()))) {
mQueriesViaPackage.add(newPkgSetting.getAppId(), existingSetting.getAppId());
+ mQueriesViaPackage.add(existingSetting.getAppId(), newPkgSetting.getAppId());
}
- if (canQueryViaUsesLibrary(newPkg, existingPkg)) {
- mQueryableViaUsesLibrary.add(newPkgSetting.getAppId(),
- existingSetting.getAppId());
- }
- }
- // if either package instruments the other, mark both as visible to one another
- if (newPkgSetting.getPkg() != null && existingSetting.getPkg() != null
- && (pkgInstruments(newPkgSetting.getPkg(), existingSetting.getPkg())
- || pkgInstruments(existingSetting.getPkg(), newPkgSetting.getPkg()))) {
- mQueriesViaPackage.add(newPkgSetting.getAppId(), existingSetting.getAppId());
- mQueriesViaPackage.add(existingSetting.getAppId(), newPkgSetting.getAppId());
}
}
@@ -845,19 +943,17 @@ public class AppsFilter implements Watchable, Snappable {
return changedPackages;
}
- @GuardedBy("mCacheLock")
private void removeAppIdFromVisibilityCache(int appId) {
- if (mShouldFilterCache == null) {
- return;
- }
- for (int i = 0; i < mShouldFilterCache.size(); i++) {
- if (UserHandle.getAppId(mShouldFilterCache.keyAt(i)) == appId) {
- mShouldFilterCache.removeAt(i);
- // The key was deleted so the list of keys has shifted left. That means i
- // is now pointing at the next key to be examined. The decrement here and
- // the loop increment together mean that i will be unchanged in the need
- // iteration and will correctly point to the next key to be examined.
- i--;
+ synchronized (mCacheLock) {
+ for (int i = 0; i < mShouldFilterCache.size(); i++) {
+ if (UserHandle.getAppId(mShouldFilterCache.keyAt(i)) == appId) {
+ mShouldFilterCache.removeAt(i);
+ // The key was deleted so the list of keys has shifted left. That means i
+ // is now pointing at the next key to be examined. The decrement here and
+ // the loop increment together mean that i will be unchanged in the need
+ // iteration and will correctly point to the next key to be examined.
+ i--;
+ }
}
}
}
@@ -883,11 +979,12 @@ public class AppsFilter implements Watchable, Snappable {
WatchedSparseBooleanMatrix cache =
updateEntireShouldFilterCacheInner(settings, users, userId);
synchronized (mCacheLock) {
- mShouldFilterCache = cache;
+ mShouldFilterCache.copyFrom(cache);
}
});
}
+ @NonNull
private WatchedSparseBooleanMatrix updateEntireShouldFilterCacheInner(
ArrayMap<String, ? extends PackageStateInternal> settings, UserInfo[] users,
int subjectUserId) {
@@ -948,36 +1045,25 @@ public class AppsFilter implements Watchable, Snappable {
}
} else {
synchronized (mCacheLock) {
- mShouldFilterCache = cache;
+ mShouldFilterCache.copyFrom(cache);
}
}
});
}
public void onUserCreated(int newUserId) {
- synchronized (mCacheLock) {
- if (mShouldFilterCache != null) {
- updateEntireShouldFilterCache(newUserId);
- onChanged();
- }
- }
+ updateEntireShouldFilterCache(newUserId);
+ onChanged();
}
public void onUserDeleted(@UserIdInt int userId) {
- synchronized (mCacheLock) {
- if (mShouldFilterCache != null) {
- removeShouldFilterCacheForUser(userId);
- onChanged();
- }
- }
+ removeShouldFilterCacheForUser(userId);
+ onChanged();
}
private void updateShouldFilterCacheForPackage(String packageName) {
mStateProvider.runWithState((settings, users) -> {
synchronized (mCacheLock) {
- if (mShouldFilterCache == null) {
- return;
- }
updateShouldFilterCacheForPackage(mShouldFilterCache, null /* skipPackage */,
settings.get(packageName), settings, users, USER_ALL,
settings.size() /*maxIndex*/);
@@ -985,7 +1071,7 @@ public class AppsFilter implements Watchable, Snappable {
});
}
- private void updateShouldFilterCacheForPackage(WatchedSparseBooleanMatrix cache,
+ private void updateShouldFilterCacheForPackage(@NonNull WatchedSparseBooleanMatrix cache,
@Nullable String skipPackageName, PackageStateInternal subjectSetting, ArrayMap<String,
? extends PackageStateInternal> allSettings, UserInfo[] allUsers, int subjectUserId,
int maxIndex) {
@@ -1011,7 +1097,7 @@ public class AppsFilter implements Watchable, Snappable {
}
}
- private void updateShouldFilterCacheForUser(WatchedSparseBooleanMatrix cache,
+ private void updateShouldFilterCacheForUser(@NonNull WatchedSparseBooleanMatrix cache,
PackageStateInternal subjectSetting, UserInfo[] allUsers,
PackageStateInternal otherSetting, int subjectUserId) {
for (int ou = 0; ou < allUsers.length; ou++) {
@@ -1027,27 +1113,28 @@ public class AppsFilter implements Watchable, Snappable {
}
}
- @GuardedBy("mCacheLock")
private void removeShouldFilterCacheForUser(int userId) {
- // Sorted uids with the ascending order
- final int[] cacheUids = mShouldFilterCache.keys();
- final int size = cacheUids.length;
- int pos = Arrays.binarySearch(cacheUids, UserHandle.getUid(userId, 0));
- final int fromIndex = (pos >= 0 ? pos : ~pos);
- if (fromIndex >= size || UserHandle.getUserId(cacheUids[fromIndex]) != userId) {
- Slog.w(TAG, "Failed to remove should filter cache for user " + userId
- + ", fromIndex=" + fromIndex);
- return;
- }
- pos = Arrays.binarySearch(cacheUids, UserHandle.getUid(userId + 1, 0) - 1);
- final int toIndex = (pos >= 0 ? pos + 1 : ~pos);
- if (fromIndex >= toIndex || UserHandle.getUserId(cacheUids[toIndex - 1]) != userId) {
- Slog.w(TAG, "Failed to remove should filter cache for user " + userId
- + ", fromIndex=" + fromIndex + ", toIndex=" + toIndex);
- return;
+ synchronized (mCacheLock) {
+ // Sorted uids with the ascending order
+ final int[] cacheUids = mShouldFilterCache.keys();
+ final int size = cacheUids.length;
+ int pos = Arrays.binarySearch(cacheUids, UserHandle.getUid(userId, 0));
+ final int fromIndex = (pos >= 0 ? pos : ~pos);
+ if (fromIndex >= size || UserHandle.getUserId(cacheUids[fromIndex]) != userId) {
+ Slog.w(TAG, "Failed to remove should filter cache for user " + userId
+ + ", fromIndex=" + fromIndex);
+ return;
+ }
+ pos = Arrays.binarySearch(cacheUids, UserHandle.getUid(userId + 1, 0) - 1);
+ final int toIndex = (pos >= 0 ? pos + 1 : ~pos);
+ if (fromIndex >= toIndex || UserHandle.getUserId(cacheUids[toIndex - 1]) != userId) {
+ Slog.w(TAG, "Failed to remove should filter cache for user " + userId
+ + ", fromIndex=" + fromIndex + ", toIndex=" + toIndex);
+ return;
+ }
+ mShouldFilterCache.removeRange(fromIndex, toIndex);
+ mShouldFilterCache.compact();
}
- mShouldFilterCache.removeRange(fromIndex, toIndex);
- mShouldFilterCache.compact();
}
private static boolean isSystemSigned(@NonNull SigningDetails sysSigningDetails,
@@ -1056,28 +1143,30 @@ public class AppsFilter implements Watchable, Snappable {
&& pkgSetting.getSigningDetails().signaturesMatchExactly(sysSigningDetails);
}
- private ArraySet<String> collectProtectedBroadcasts(
+ private void collectProtectedBroadcasts(
ArrayMap<String, ? extends PackageStateInternal> existingSettings,
@Nullable String excludePackage) {
- ArraySet<String> ret = new ArraySet<>();
- for (int i = existingSettings.size() - 1; i >= 0; i--) {
- PackageStateInternal setting = existingSettings.valueAt(i);
- if (setting.getPkg() == null || setting.getPkg().getPackageName().equals(
- excludePackage)) {
- continue;
- }
- final List<String> protectedBroadcasts = setting.getPkg().getProtectedBroadcasts();
- if (!protectedBroadcasts.isEmpty()) {
- ret.addAll(protectedBroadcasts);
+ synchronized (mLock) {
+ mProtectedBroadcasts.clear();
+ for (int i = existingSettings.size() - 1; i >= 0; i--) {
+ PackageStateInternal setting = existingSettings.valueAt(i);
+ if (setting.getPkg() == null || setting.getPkg().getPackageName().equals(
+ excludePackage)) {
+ continue;
+ }
+ final List<String> protectedBroadcasts = setting.getPkg().getProtectedBroadcasts();
+ if (!protectedBroadcasts.isEmpty()) {
+ mProtectedBroadcasts.addAll(protectedBroadcasts);
+ }
}
}
- return ret;
}
/**
* This method recomputes all component / intent-based visibility and is intended to match the
* relevant logic of {@link #addPackageInternal(PackageStateInternal, ArrayMap)}
*/
+ @GuardedBy("mLock")
private void recomputeComponentVisibility(
ArrayMap<String, ? extends PackageStateInternal> existingSettings) {
mQueriesViaComponent.clear();
@@ -1105,24 +1194,16 @@ public class AppsFilter implements Watchable, Snappable {
}
/**
- * Fetches all app Ids that a given setting is currently visible to, per provided user. This
- * only includes UIDs >= {@link Process#FIRST_APPLICATION_UID} as all other UIDs can already see
- * all applications.
- *
- * If the setting is visible to all UIDs, null is returned. If an app is not visible to any
- * applications, the int array will be empty.
- *
- * @param users the set of users that should be evaluated for this calculation
- * @param existingSettings the set of all package settings that currently exist on device
- * @return a SparseArray mapping userIds to a sorted int array of appIds that may view the
- * provided setting or null if the app is visible to all and no allow list should be
- * applied.
+ * See {@link AppsFilterSnapshot#getVisibilityAllowList(PackageStateInternal, int[], ArrayMap)}
*/
+ @Override
@Nullable
public SparseArray<int[]> getVisibilityAllowList(PackageStateInternal setting, int[] users,
ArrayMap<String, ? extends PackageStateInternal> existingSettings) {
- if (mForceQueryable.contains(setting.getAppId())) {
- return null;
+ synchronized (mLock) {
+ if (mForceQueryable.contains(setting.getAppId())) {
+ return null;
+ }
}
// let's reserve max memory to limit the number of allocations
SparseArray<int[]> result = new SparseArray<>(users.length);
@@ -1171,7 +1252,8 @@ public class AppsFilter implements Watchable, Snappable {
/**
* Equivalent to calling {@link #addPackage(PackageStateInternal, boolean)} with
* {@code isReplace} equal to {@code false}.
- * @see AppsFilter#addPackage(PackageStateInternal, boolean)
+ *
+ * @see AppsFilterImpl#addPackage(PackageStateInternal, boolean)
*/
public void addPackage(PackageStateInternal newPkgSetting) {
addPackage(newPkgSetting, false /* isReplace */);
@@ -1180,62 +1262,68 @@ public class AppsFilter implements Watchable, Snappable {
/**
* Removes a package for consideration when filtering visibility between apps.
*
- * @param setting the setting of the package being removed.
+ * @param setting the setting of the package being removed.
* @param isReplace if the package is being replaced.
*/
public void removePackage(PackageStateInternal setting, boolean isReplace) {
mStateProvider.runWithState((settings, users) -> {
- final int userCount = users.length;
- for (int u = 0; u < userCount; u++) {
- final int userId = users[u].id;
- final int removingUid = UserHandle.getUid(userId, setting.getAppId());
- mImplicitlyQueryable.remove(removingUid);
- for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) {
- mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), removingUid);
- }
+ final ArraySet<String> additionalChangedPackages;
+ synchronized (mLock) {
+ final int userCount = users.length;
+ for (int u = 0; u < userCount; u++) {
+ final int userId = users[u].id;
+ final int removingUid = UserHandle.getUid(userId, setting.getAppId());
+ mImplicitlyQueryable.remove(removingUid);
+ for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) {
+ mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), removingUid);
+ }
- if (isReplace) {
- continue;
- }
+ if (isReplace) {
+ continue;
+ }
- mRetainedImplicitlyQueryable.remove(removingUid);
- for (int i = mRetainedImplicitlyQueryable.size() - 1; i >= 0; i--) {
- mRetainedImplicitlyQueryable.remove(
- mRetainedImplicitlyQueryable.keyAt(i), removingUid);
+ mRetainedImplicitlyQueryable.remove(removingUid);
+ for (int i = mRetainedImplicitlyQueryable.size() - 1; i >= 0; i--) {
+ mRetainedImplicitlyQueryable.remove(
+ mRetainedImplicitlyQueryable.keyAt(i), removingUid);
+ }
}
- }
- if (!mQueriesViaComponentRequireRecompute) {
- mQueriesViaComponent.remove(setting.getAppId());
- for (int i = mQueriesViaComponent.size() - 1; i >= 0; i--) {
- mQueriesViaComponent.remove(mQueriesViaComponent.keyAt(i), setting.getAppId());
+ if (!mQueriesViaComponentRequireRecompute) {
+ mQueriesViaComponent.remove(setting.getAppId());
+ for (int i = mQueriesViaComponent.size() - 1; i >= 0; i--) {
+ mQueriesViaComponent.remove(mQueriesViaComponent.keyAt(i),
+ setting.getAppId());
+ }
+ }
+ mQueriesViaPackage.remove(setting.getAppId());
+ for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) {
+ mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.getAppId());
+ }
+ mQueryableViaUsesLibrary.remove(setting.getAppId());
+ for (int i = mQueryableViaUsesLibrary.size() - 1; i >= 0; i--) {
+ mQueryableViaUsesLibrary.remove(mQueryableViaUsesLibrary.keyAt(i),
+ setting.getAppId());
}
- }
- mQueriesViaPackage.remove(setting.getAppId());
- for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) {
- mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.getAppId());
- }
- mQueryableViaUsesLibrary.remove(setting.getAppId());
- for (int i = mQueryableViaUsesLibrary.size() - 1; i >= 0; i--) {
- mQueryableViaUsesLibrary.remove(mQueryableViaUsesLibrary.keyAt(i),
- setting.getAppId());
- }
- mForceQueryable.remove(setting.getAppId());
+ mForceQueryable.remove(setting.getAppId());
- if (setting.getPkg() != null && !setting.getPkg().getProtectedBroadcasts().isEmpty()) {
- final String removingPackageName = setting.getPkg().getPackageName();
- final Set<String> protectedBroadcasts = mProtectedBroadcasts;
- mProtectedBroadcasts = collectProtectedBroadcasts(settings, removingPackageName);
- if (!mProtectedBroadcasts.containsAll(protectedBroadcasts)) {
- mQueriesViaComponentRequireRecompute = true;
+ if (setting.getPkg() != null
+ && !setting.getPkg().getProtectedBroadcasts().isEmpty()) {
+ final String removingPackageName = setting.getPkg().getPackageName();
+ final ArrayList<String> protectedBroadcasts = new ArrayList<>();
+ protectedBroadcasts.addAll(mProtectedBroadcasts.untrackedStorage());
+ collectProtectedBroadcasts(settings, removingPackageName);
+ if (!mProtectedBroadcasts.containsAll(protectedBroadcasts)) {
+ mQueriesViaComponentRequireRecompute = true;
+ }
}
- }
- ArraySet<String> additionalChangedPackages =
- mOverlayReferenceMapper.removePkg(setting.getPackageName());
+ additionalChangedPackages =
+ mOverlayReferenceMapper.removePkg(setting.getPackageName());
- mFeatureConfig.updatePackageState(setting, true /*removed*/);
+ mFeatureConfig.updatePackageState(setting, true /*removed*/);
+ }
// After removing all traces of the package, if it's part of a shared user, re-add other
// shared user members to re-establish visibility between them and other packages.
@@ -1253,56 +1341,49 @@ public class AppsFilter implements Watchable, Snappable {
}
}
- synchronized (mCacheLock) {
- removeAppIdFromVisibilityCache(setting.getAppId());
- if (mShouldFilterCache != null && setting.hasSharedUser()) {
- final ArraySet<PackageStateInternal> sharedUserPackages =
- mPmInternal.getSharedUserPackages(setting.getSharedUserAppId());
- for (int i = sharedUserPackages.size() - 1; i >= 0; i--) {
- PackageStateInternal siblingSetting =
- sharedUserPackages.valueAt(i);
- if (siblingSetting == setting) {
- continue;
- }
+ removeAppIdFromVisibilityCache(setting.getAppId());
+ if (setting.hasSharedUser()) {
+ final ArraySet<PackageStateInternal> sharedUserPackages =
+ mPmInternal.getSharedUserPackages(setting.getSharedUserAppId());
+ for (int i = sharedUserPackages.size() - 1; i >= 0; i--) {
+ PackageStateInternal siblingSetting =
+ sharedUserPackages.valueAt(i);
+ if (siblingSetting == setting) {
+ continue;
+ }
+ synchronized (mCacheLock) {
updateShouldFilterCacheForPackage(mShouldFilterCache,
setting.getPackageName(), siblingSetting, settings, users,
USER_ALL, settings.size());
}
}
+ }
- if (mShouldFilterCache != null) {
- if (additionalChangedPackages != null) {
- for (int index = 0; index < additionalChangedPackages.size(); index++) {
- String changedPackage = additionalChangedPackages.valueAt(index);
- PackageStateInternal changedPkgSetting = settings.get(changedPackage);
- if (changedPkgSetting == null) {
- // It's possible for the overlay mapper to know that an actor
- // package changed via an explicit reference, even if the actor
- // isn't installed, so skip if that's the case.
- continue;
- }
-
- updateShouldFilterCacheForPackage(mShouldFilterCache, null,
- changedPkgSetting, settings, users, USER_ALL, settings.size());
- }
+ if (additionalChangedPackages != null) {
+ for (int index = 0; index < additionalChangedPackages.size(); index++) {
+ String changedPackage = additionalChangedPackages.valueAt(index);
+ PackageStateInternal changedPkgSetting = settings.get(changedPackage);
+ if (changedPkgSetting == null) {
+ // It's possible for the overlay mapper to know that an actor
+ // package changed via an explicit reference, even if the actor
+ // isn't installed, so skip if that's the case.
+ continue;
+ }
+ synchronized (mCacheLock) {
+ updateShouldFilterCacheForPackage(mShouldFilterCache, null,
+ changedPkgSetting, settings, users, USER_ALL, settings.size());
}
}
-
- onChanged();
}
+ onChanged();
});
}
/**
- * Returns true if the calling package should not be able to see the target package, false if no
- * filtering should be done.
- *
- * @param callingUid the uid of the caller attempting to access a package
- * @param callingSetting the setting attempting to access a package or null if it could not be
- * found
- * @param targetPkgSetting the package being accessed
- * @param userId the user in which this access is being attempted
+ * See {@link AppsFilterSnapshot#shouldFilterApplication(int, Object, PackageStateInternal,
+ * int)}
*/
+ @Override
public boolean shouldFilterApplication(int callingUid, @Nullable Object callingSetting,
PackageStateInternal targetPkgSetting, int userId) {
if (DEBUG_TRACING) {
@@ -1315,31 +1396,22 @@ public class AppsFilter implements Watchable, Snappable {
|| callingAppId == targetPkgSetting.getAppId()) {
return false;
}
+ final boolean shouldUseCache;
synchronized (mCacheLock) {
- if (mShouldFilterCache != null) { // use cache
- final int callingIndex = mShouldFilterCache.indexOfKey(callingUid);
- if (callingIndex < 0) {
- Slog.wtf(TAG, "Encountered calling uid with no cached rules: "
- + callingUid);
- return true;
- }
- final int targetUid = UserHandle.getUid(userId, targetPkgSetting.getAppId());
- final int targetIndex = mShouldFilterCache.indexOfKey(targetUid);
- if (targetIndex < 0) {
- Slog.w(TAG, "Encountered calling -> target with no cached rules: "
- + callingUid + " -> " + targetUid);
- return true;
- }
- if (!mShouldFilterCache.valueAt(callingIndex, targetIndex)) {
- return false;
- }
- } else {
- if (!shouldFilterApplicationInternal(
- callingUid, callingSetting, targetPkgSetting, userId)) {
- return false;
- }
+ shouldUseCache = mShouldFilterCache.size() != 0;
+ }
+ if (shouldUseCache) { // use cache
+ if (!shouldFilterApplicationUsingCache(callingUid, targetPkgSetting.getAppId(),
+ userId)) {
+ return false;
+ }
+ } else {
+ if (!shouldFilterApplicationInternal(
+ callingUid, callingSetting, targetPkgSetting, userId)) {
+ return false;
}
}
+
if (DEBUG_LOGGING || mFeatureConfig.isLoggingEnabled(callingAppId)) {
log(callingSetting, targetPkgSetting, "BLOCKED");
}
@@ -1351,6 +1423,25 @@ public class AppsFilter implements Watchable, Snappable {
}
}
+ private boolean shouldFilterApplicationUsingCache(int callingUid, int appId, int userId) {
+ synchronized (mCacheLock) {
+ final int callingIndex = mShouldFilterCache.indexOfKey(callingUid);
+ if (callingIndex < 0) {
+ Slog.wtf(TAG, "Encountered calling uid with no cached rules: "
+ + callingUid);
+ return true;
+ }
+ final int targetUid = UserHandle.getUid(userId, appId);
+ final int targetIndex = mShouldFilterCache.indexOfKey(targetUid);
+ if (targetIndex < 0) {
+ Slog.w(TAG, "Encountered calling -> target with no cached rules: "
+ + callingUid + " -> " + targetUid);
+ return true;
+ }
+ return mShouldFilterCache.valueAt(callingIndex, targetIndex);
+ }
+ }
+
private boolean shouldFilterApplicationInternal(int callingUid, Object callingSetting,
PackageStateInternal targetPkgSetting, int targetUserId) {
if (DEBUG_TRACING) {
@@ -1437,10 +1528,10 @@ public class AppsFilter implements Watchable, Snappable {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "requestsQueryAllPackages");
}
if (callingPkgSetting != null) {
- if (callingPkgSetting.getPkg() != null
- && requestsQueryAllPackages(callingPkgSetting.getPkg())) {
- return false;
- }
+ if (callingPkgSetting.getPkg() != null
+ && requestsQueryAllPackages(callingPkgSetting.getPkg())) {
+ return false;
+ }
} else {
for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) {
AndroidPackage pkg = callingSharedPkgSettings.valueAt(i).getPkg();
@@ -1469,142 +1560,147 @@ public class AppsFilter implements Watchable, Snappable {
return false;
}
- try {
- if (DEBUG_TRACING) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mForceQueryable");
- }
- if (mForceQueryable.contains(targetAppId)) {
- if (DEBUG_LOGGING) {
- log(callingSetting, targetPkgSetting, "force queryable");
+ synchronized (mLock) {
+ try {
+ if (DEBUG_TRACING) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mForceQueryable");
}
- return false;
- }
- } finally {
- if (DEBUG_TRACING) {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
- try {
- if (DEBUG_TRACING) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueriesViaPackage");
- }
- if (mQueriesViaPackage.contains(callingAppId, targetAppId)) {
- if (DEBUG_LOGGING) {
- log(callingSetting, targetPkgSetting, "queries package");
+ if (mForceQueryable.contains(targetAppId)) {
+ if (DEBUG_LOGGING) {
+ log(callingSetting, targetPkgSetting, "force queryable");
+ }
+ return false;
+ }
+ } finally {
+ if (DEBUG_TRACING) {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- return false;
- }
- } finally {
- if (DEBUG_TRACING) {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
- try {
- if (DEBUG_TRACING) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueriesViaComponent");
- }
- if (mQueriesViaComponentRequireRecompute) {
- mStateProvider.runWithState((settings, users) -> {
- recomputeComponentVisibility(settings);
- });
}
- if (mQueriesViaComponent.contains(callingAppId, targetAppId)) {
- if (DEBUG_LOGGING) {
- log(callingSetting, targetPkgSetting, "queries component");
+ try {
+ if (DEBUG_TRACING) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueriesViaPackage");
+ }
+ if (mQueriesViaPackage.contains(callingAppId, targetAppId)) {
+ if (DEBUG_LOGGING) {
+ log(callingSetting, targetPkgSetting, "queries package");
+ }
+ return false;
+ }
+ } finally {
+ if (DEBUG_TRACING) {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- return false;
}
- } finally {
- if (DEBUG_TRACING) {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ try {
+ if (DEBUG_TRACING) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueriesViaComponent");
+ }
+ if (mQueriesViaComponentRequireRecompute) {
+ mStateProvider.runWithState((settings, users) -> {
+ synchronized (mLock) {
+ recomputeComponentVisibility(settings);
+ }
+ });
+ }
+ if (mQueriesViaComponent.contains(callingAppId, targetAppId)) {
+ if (DEBUG_LOGGING) {
+ log(callingSetting, targetPkgSetting, "queries component");
+ }
+ return false;
+ }
+ } finally {
+ if (DEBUG_TRACING) {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
}
- }
- try {
- if (DEBUG_TRACING) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mImplicitlyQueryable");
- }
- final int targetUid = UserHandle.getUid(targetUserId, targetAppId);
- if (mImplicitlyQueryable.contains(callingUid, targetUid)) {
- if (DEBUG_LOGGING) {
- log(callingSetting, targetPkgSetting, "implicitly queryable for user");
+ try {
+ if (DEBUG_TRACING) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mImplicitlyQueryable");
+ }
+ final int targetUid = UserHandle.getUid(targetUserId, targetAppId);
+ if (mImplicitlyQueryable.contains(callingUid, targetUid)) {
+ if (DEBUG_LOGGING) {
+ log(callingSetting, targetPkgSetting, "implicitly queryable for user");
+ }
+ return false;
+ }
+ } finally {
+ if (DEBUG_TRACING) {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- return false;
- }
- } finally {
- if (DEBUG_TRACING) {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- }
- try {
- if (DEBUG_TRACING) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mRetainedImplicitlyQueryable");
- }
- final int targetUid = UserHandle.getUid(targetUserId, targetAppId);
- if (mRetainedImplicitlyQueryable.contains(callingUid, targetUid)) {
- if (DEBUG_LOGGING) {
- log(callingSetting, targetPkgSetting,
- "retained implicitly queryable for user");
+ try {
+ if (DEBUG_TRACING) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mRetainedImplicitlyQueryable");
+ }
+ final int targetUid = UserHandle.getUid(targetUserId, targetAppId);
+ if (mRetainedImplicitlyQueryable.contains(callingUid, targetUid)) {
+ if (DEBUG_LOGGING) {
+ log(callingSetting, targetPkgSetting,
+ "retained implicitly queryable for user");
+ }
+ return false;
+ }
+ } finally {
+ if (DEBUG_TRACING) {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- return false;
- }
- } finally {
- if (DEBUG_TRACING) {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- }
- try {
- if (DEBUG_TRACING) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mOverlayReferenceMapper");
- }
- final String targetName = targetPkg.getPackageName();
- if (callingSharedPkgSettings != null) {
- int size = callingSharedPkgSettings.size();
- for (int index = 0; index < size; index++) {
- PackageStateInternal pkgSetting = callingSharedPkgSettings.valueAt(index);
+ try {
+ if (DEBUG_TRACING) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mOverlayReferenceMapper");
+ }
+ final String targetName = targetPkg.getPackageName();
+ if (callingSharedPkgSettings != null) {
+ int size = callingSharedPkgSettings.size();
+ for (int index = 0; index < size; index++) {
+ PackageStateInternal pkgSetting = callingSharedPkgSettings.valueAt(
+ index);
+ if (mOverlayReferenceMapper.isValidActor(targetName,
+ pkgSetting.getPackageName())) {
+ if (DEBUG_LOGGING) {
+ log(callingPkgSetting, targetPkgSetting,
+ "matches shared user of package that acts on target of "
+ + "overlay");
+ }
+ return false;
+ }
+ }
+ } else {
if (mOverlayReferenceMapper.isValidActor(targetName,
- pkgSetting.getPackageName())) {
+ callingPkgSetting.getPackageName())) {
if (DEBUG_LOGGING) {
log(callingPkgSetting, targetPkgSetting,
- "matches shared user of package that acts on target of "
- + "overlay");
+ "acts on target of overlay");
}
return false;
}
}
- } else {
- if (mOverlayReferenceMapper.isValidActor(targetName,
- callingPkgSetting.getPackageName())) {
+ } finally {
+ if (DEBUG_TRACING) {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ try {
+ if (DEBUG_TRACING) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueryableViaUsesLibrary");
+ }
+ if (mQueryableViaUsesLibrary.contains(callingAppId, targetAppId)) {
if (DEBUG_LOGGING) {
- log(callingPkgSetting, targetPkgSetting, "acts on target of overlay");
+ log(callingSetting, targetPkgSetting, "queryable for library users");
}
return false;
}
- }
- } finally {
- if (DEBUG_TRACING) {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
-
- try {
- if (DEBUG_TRACING) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueryableViaUsesLibrary");
- }
- if (mQueryableViaUsesLibrary.contains(callingAppId, targetAppId)) {
- if (DEBUG_LOGGING) {
- log(callingSetting, targetPkgSetting, "queryable for library users");
+ } finally {
+ if (DEBUG_TRACING) {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- return false;
- }
- } finally {
- if (DEBUG_TRACING) {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
-
return true;
} finally {
if (DEBUG_TRACING) {
@@ -1613,7 +1709,11 @@ public class AppsFilter implements Watchable, Snappable {
}
}
- boolean canQueryPackage(@NonNull AndroidPackage querying, String potentialTarget) {
+ /**
+ * See {@link AppsFilterSnapshot#canQueryPackage(AndroidPackage, String)}
+ */
+ @Override
+ public boolean canQueryPackage(@NonNull AndroidPackage querying, String potentialTarget) {
int appId = UserHandle.getAppId(querying.getUid());
if (appId < Process.FIRST_APPLICATION_UID) {
return true;
@@ -1668,6 +1768,11 @@ public class AppsFilter implements Watchable, Snappable {
+ targetPkgSetting + " " + description);
}
+ /**
+ * See {@link AppsFilterSnapshot#dumpQueries(PrintWriter, Integer, DumpState, int[],
+ * QuadFunction)}
+ */
+ @Override
public void dumpQueries(
PrintWriter pw, @Nullable Integer filteringAppId, DumpState dumpState, int[] users,
QuadFunction<Integer, Integer, Integer, Boolean, String[]> getPackagesForUid) {
@@ -1702,27 +1807,30 @@ public class AppsFilter implements Watchable, Snappable {
}
}
pw.println(" system apps queryable: " + mSystemAppsQueryable);
- dumpPackageSet(pw, filteringAppId, mForceQueryable, "forceQueryable", " ", expandPackages);
- pw.println(" queries via package name:");
- dumpQueriesMap(pw, filteringAppId, mQueriesViaPackage, " ", expandPackages);
- pw.println(" queries via component:");
- dumpQueriesMap(pw, filteringAppId, mQueriesViaComponent, " ", expandPackages);
- pw.println(" queryable via interaction:");
- for (int user : users) {
- pw.append(" User ").append(Integer.toString(user)).println(":");
- dumpQueriesMap(pw,
- filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId),
- mImplicitlyQueryable, " ", expandPackages);
- dumpQueriesMap(pw,
- filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId),
- mRetainedImplicitlyQueryable, " ", expandPackages);
+ synchronized (mLock) {
+ dumpPackageSet(pw, filteringAppId, mForceQueryable.untrackedStorage(),
+ "forceQueryable", " ", expandPackages);
+ pw.println(" queries via package name:");
+ dumpQueriesMap(pw, filteringAppId, mQueriesViaPackage, " ", expandPackages);
+ pw.println(" queries via component:");
+ dumpQueriesMap(pw, filteringAppId, mQueriesViaComponent, " ", expandPackages);
+ pw.println(" queryable via interaction:");
+ for (int user : users) {
+ pw.append(" User ").append(Integer.toString(user)).println(":");
+ dumpQueriesMap(pw,
+ filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId),
+ mImplicitlyQueryable, " ", expandPackages);
+ dumpQueriesMap(pw,
+ filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId),
+ mRetainedImplicitlyQueryable, " ", expandPackages);
+ }
+ pw.println(" queryable via uses-library:");
+ dumpQueriesMap(pw, filteringAppId, mQueryableViaUsesLibrary, " ", expandPackages);
}
- pw.println(" queryable via uses-library:");
- dumpQueriesMap(pw, filteringAppId, mQueryableViaUsesLibrary, " ", expandPackages);
}
private static void dumpQueriesMap(PrintWriter pw, @Nullable Integer filteringId,
- SparseSetArray<Integer> queriesMap, String spacing,
+ WatchedSparseSetArray<Integer> queriesMap, String spacing,
@Nullable ToString<Integer> toString) {
for (int i = 0; i < queriesMap.size(); i++) {
Integer callingId = queriesMap.keyAt(i);
@@ -1750,7 +1858,7 @@ public class AppsFilter implements Watchable, Snappable {
}
private static <T> void dumpPackageSet(PrintWriter pw, @Nullable T filteringId,
- Set<T> targetPkgSet, String subTitle, String spacing,
+ ArraySet<T> targetPkgSet, String subTitle, String spacing,
@Nullable ToString<T> toString) {
if (targetPkgSet != null && targetPkgSet.size() > 0
&& (filteringId == null || targetPkgSet.contains(filteringId))) {
diff --git a/services/core/java/com/android/server/pm/AppsFilterSnapshot.java b/services/core/java/com/android/server/pm/AppsFilterSnapshot.java
new file mode 100644
index 000000000000..cb8c649ded00
--- /dev/null
+++ b/services/core/java/com/android/server/pm/AppsFilterSnapshot.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Process;
+import android.util.ArrayMap;
+import android.util.SparseArray;
+
+import com.android.internal.util.function.QuadFunction;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.PackageStateInternal;
+
+import java.io.PrintWriter;
+
+/**
+ * Read-only interface used by computer and snapshots to query the visibility of packages
+ */
+public interface AppsFilterSnapshot {
+ /**
+ * Fetches all app Ids that a given setting is currently visible to, per provided user. This
+ * only includes UIDs >= {@link Process#FIRST_APPLICATION_UID} as all other UIDs can already see
+ * all applications.
+ *
+ * If the setting is visible to all UIDs, null is returned. If an app is not visible to any
+ * applications, the int array will be empty.
+ *
+ * @param users the set of users that should be evaluated for this calculation
+ * @param existingSettings the set of all package settings that currently exist on device
+ * @return a SparseArray mapping userIds to a sorted int array of appIds that may view the
+ * provided setting or null if the app is visible to all and no allow list should be
+ * applied.
+ */
+ SparseArray<int[]> getVisibilityAllowList(PackageStateInternal setting, int[] users,
+ ArrayMap<String, ? extends PackageStateInternal> existingSettings);
+
+ /**
+ * Returns true if the calling package should not be able to see the target package, false if no
+ * filtering should be done.
+ *
+ * @param callingUid the uid of the caller attempting to access a package
+ * @param callingSetting the setting attempting to access a package or null if it could not be
+ * found
+ * @param targetPkgSetting the package being accessed
+ * @param userId the user in which this access is being attempted
+ */
+ boolean shouldFilterApplication(int callingUid, @Nullable Object callingSetting,
+ PackageStateInternal targetPkgSetting, int userId);
+
+ /**
+ * Returns whether the querying package is allowed to see the target package.
+ *
+ * @param querying the querying package
+ * @param potentialTarget the package name of the target package
+ */
+ boolean canQueryPackage(@NonNull AndroidPackage querying, String potentialTarget);
+
+ /**
+ * Dump the packages that are queryable by the querying package.
+ *
+ * @param pw the output print writer
+ * @param filteringAppId the querying package's app ID
+ * @param dumpState the state of the dumping
+ * @param users the users for which the packages are installed
+ * @param getPackagesForUid the function that produces the package names for given uids
+ */
+ void dumpQueries(PrintWriter pw, @Nullable Integer filteringAppId, DumpState dumpState,
+ int[] users,
+ QuadFunction<Integer, Integer, Integer, Boolean, String[]> getPackagesForUid);
+
+}
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index f1394d403bf7..bf1196d6b969 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -320,17 +320,6 @@ public final class BroadcastHelper {
broadcastAllowlist, null);
}
- public void sendDistractingPackagesChanged(String[] pkgList, int[] uidList, int userId,
- int distractionFlags) {
- final Bundle extras = new Bundle(3);
- extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
- extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList);
- extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, distractionFlags);
- sendPackageBroadcast(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED, null, extras,
- Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null, new int[]{userId}, null, null,
- null);
- }
-
public void sendFirstLaunchBroadcast(String pkgName, String installerPkg,
int[] userIds, int[] instantUserIds) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0,
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index 8e853019de90..3e204b6e6e4c 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -45,6 +45,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Pair;
import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -571,6 +572,31 @@ public interface Computer extends PackageDataSnapshot {
@NonNull
WatchedArrayMap<String, Integer> getFrozenPackages();
+ /**
+ * Verify that given package is currently frozen.
+ */
+ void checkPackageFrozen(@NonNull String packageName);
+
@Nullable
ComponentName getInstantAppInstallerComponent();
+
+ void dumpPermissions(@NonNull PrintWriter pw, @NonNull String packageName,
+ @NonNull ArraySet<String> permissionNames, @NonNull DumpState dumpState);
+
+ void dumpPackages(PrintWriter pw, @NonNull String packageName,
+ @NonNull ArraySet<String> permissionNames, @NonNull DumpState dumpState,
+ boolean checkin);
+
+ void dumpKeySet(@NonNull PrintWriter pw, @NonNull String packageName,
+ @NonNull DumpState dumpState);
+
+ void dumpSharedUsers(@NonNull PrintWriter pw, @NonNull String packageName,
+ @NonNull ArraySet<String> permissionNames,
+ @NonNull DumpState dumpState, boolean checkin);
+
+ void dumpSharedUsersProto(@NonNull ProtoOutputStream proto);
+
+ void dumpPackagesProto(@NonNull ProtoOutputStream proto);
+
+ void dumpSharedLibrariesProto(@NonNull ProtoOutputStream protoOutputStream);
}
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 4abfd3404295..8ac3dca1991d 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -117,6 +117,7 @@ import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.TypedXmlSerializer;
import android.util.Xml;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -322,6 +323,37 @@ public class ComputerEngine implements Computer {
}
return res;
}
+
+ public void dumpPackagesProto(ProtoOutputStream proto) {
+ mSettings.dumpPackagesProto(proto);
+ }
+
+ public void dumpPermissions(PrintWriter pw, String packageName,
+ ArraySet<String> permissionNames, DumpState dumpState) {
+ mSettings.dumpPermissions(pw, packageName, permissionNames, dumpState);
+ }
+
+ public void dumpPackages(PrintWriter pw, String packageName,
+ ArraySet<String> permissionNames, DumpState dumpState, boolean checkin) {
+ mSettings.dumpPackagesLPr(pw, packageName, permissionNames, dumpState, checkin);
+ }
+
+ public void dumpKeySet(PrintWriter pw, String packageName, DumpState dumpState) {
+ mSettings.getKeySetManagerService().dumpLPr(pw, packageName, dumpState);
+ }
+
+ public void dumpSharedUsers(PrintWriter pw, String packageName,
+ ArraySet<String> permissionNames, DumpState dumpState, boolean checkin) {
+ mSettings.dumpSharedUsersLPr(pw, packageName, permissionNames, dumpState, checkin);
+ }
+
+ public void dumpReadMessages(PrintWriter pw, DumpState dumpState) {
+ mSettings.dumpReadMessages(pw, dumpState);
+ }
+
+ public void dumpSharedUsersProto(ProtoOutputStream proto) {
+ mSettings.dumpSharedUsersProto(proto);
+ }
}
private static final Comparator<ProviderInfo> sProviderInitOrderSorter = (p1, p2) -> {
@@ -348,7 +380,7 @@ public class ComputerEngine implements Computer {
private final ResolveInfo mInstantAppInstallerInfo;
private final InstantAppRegistry mInstantAppRegistry;
private final ApplicationInfo mLocalAndroidApplication;
- private final AppsFilter mAppsFilter;
+ private final AppsFilterSnapshot mAppsFilter;
private final WatchedArrayMap<String, Integer> mFrozenPackages;
// Immutable service attribute
@@ -3211,6 +3243,34 @@ public class ComputerEngine implements Computer {
}
break;
}
+
+ case DumpState.DUMP_MESSAGES: {
+ mSettings.dumpReadMessages(pw, dumpState);
+ break;
+ }
+
+ case DumpState.DUMP_FROZEN: {
+ // XXX should handle packageName != null by dumping only install data that
+ // the given package is involved with.
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ ipw.println();
+ ipw.println("Frozen packages:");
+ ipw.increaseIndent();
+ if (mFrozenPackages.size() == 0) {
+ ipw.println("(none)");
+ } else {
+ for (int i = 0; i < mFrozenPackages.size(); i++) {
+ ipw.print("package=");
+ ipw.print(mFrozenPackages.keyAt(i));
+ ipw.print(", refCounts=");
+ ipw.println(mFrozenPackages.valueAt(i));
+ }
+ }
+ ipw.decreaseIndent();
+ }
} // switch
}
@@ -5698,10 +5758,58 @@ public class ComputerEngine implements Computer {
return mFrozenPackages;
}
+ @Override
+ public void checkPackageFrozen(@NonNull String packageName) {
+ if (!mFrozenPackages.containsKey(packageName)) {
+ Slog.wtf(TAG, "Expected " + packageName + " to be frozen!", new Throwable());
+ }
+ }
+
@Nullable
@Override
public ComponentName getInstantAppInstallerComponent() {
return mLocalInstantAppInstallerActivity == null
? null : mLocalInstantAppInstallerActivity.getComponentName();
}
+
+ @Override
+ public void dumpPermissions(@NonNull PrintWriter pw, @NonNull String packageName,
+ @NonNull ArraySet<String> permissionNames, @NonNull DumpState dumpState) {
+ mSettings.dumpPermissions(pw, packageName, permissionNames, dumpState);
+ }
+
+ @Override
+ public void dumpPackages(@NonNull PrintWriter pw, @NonNull String packageName,
+ @NonNull ArraySet<String> permissionNames, @NonNull DumpState dumpState,
+ boolean checkin) {
+ mSettings.dumpPackages(pw, packageName, permissionNames, dumpState, checkin);
+ }
+
+ @Override
+ public void dumpKeySet(@NonNull PrintWriter pw, @NonNull String packageName,
+ @NonNull DumpState dumpState) {
+ mSettings.dumpKeySet(pw, packageName, dumpState);
+ }
+
+ @Override
+ public void dumpSharedUsers(@NonNull PrintWriter pw, @NonNull String packageName,
+ @NonNull ArraySet<String> permissionNames, @NonNull DumpState dumpState,
+ boolean checkin) {
+ mSettings.dumpSharedUsers(pw, packageName, permissionNames, dumpState, checkin);
+ }
+
+ @Override
+ public void dumpSharedUsersProto(@NonNull ProtoOutputStream proto) {
+ mSettings.dumpSharedUsersProto(proto);
+ }
+
+ @Override
+ public void dumpPackagesProto(@NonNull ProtoOutputStream proto) {
+ mSettings.dumpPackagesProto(proto);
+ }
+
+ @Override
+ public void dumpSharedLibrariesProto(@NonNull ProtoOutputStream proto) {
+ mSharedLibraries.dumpProto(proto);
+ }
}
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index dc4dd12b3a18..7dae22a44cc5 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -167,6 +167,7 @@ final class DeletePackageHelper {
if (userInfo == null || !userInfo.isAdmin()) {
Slog.w(TAG, "Not removing package " + packageName
+ " as only admin user may downgrade system apps");
+ EventLog.writeEvent(0x534e4554, "170646036", -1, packageName);
return PackageManager.DELETE_FAILED_USER_RESTRICTED;
}
}
diff --git a/services/core/java/com/android/server/pm/DistractingPackageHelper.java b/services/core/java/com/android/server/pm/DistractingPackageHelper.java
new file mode 100644
index 000000000000..7dc45b58a773
--- /dev/null
+++ b/services/core/java/com/android/server/pm/DistractingPackageHelper.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.content.pm.PackageManager.RESTRICTION_NONE;
+
+import android.annotation.NonNull;
+import android.content.Intent;
+import android.content.pm.PackageManager.DistractionRestriction;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.IntArray;
+import android.util.Slog;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.pkg.PackageStateInternal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Mark, unmark, or remove any {@link DistractionRestriction restrictions} set on given packages.
+ */
+public final class DistractingPackageHelper {
+
+ // TODO(b/198166813): remove PMS dependency
+ private final PackageManagerService mPm;
+ private final PackageManagerServiceInjector mInjector;
+ private final BroadcastHelper mBroadcastHelper;
+ private final SuspendPackageHelper mSuspendPackageHelper;
+
+ /**
+ * Constructor for {@link PackageManagerService}.
+ */
+ DistractingPackageHelper(PackageManagerService pm, PackageManagerServiceInjector injector,
+ BroadcastHelper broadcastHelper, SuspendPackageHelper suspendPackageHelper) {
+ mPm = pm;
+ mInjector = injector;
+ mBroadcastHelper = broadcastHelper;
+ mSuspendPackageHelper = suspendPackageHelper;
+ }
+
+ /**
+ * Mark or unmark the given packages as distracting to the given user.
+ *
+ * @param packageNames Packages to mark as distracting.
+ * @param restrictionFlags Any combination of restrictions to impose on the given packages.
+ * {@link DistractionRestriction#RESTRICTION_NONE} can be used to
+ * clear any existing restrictions.
+ * @param userId the user for which changes are taking place.
+ * @param callingUid The caller's uid.
+ *
+ * @return A list of packages that could not have the {@code restrictionFlags} set. The system
+ * may prevent restricting critical packages to preserve normal device function.
+ */
+ String[] setDistractingPackageRestrictionsAsUser(@NonNull Computer snapshot,
+ String[] packageNames, int restrictionFlags, int userId, int callingUid) {
+ if (ArrayUtils.isEmpty(packageNames)) {
+ return packageNames;
+ }
+ if (restrictionFlags != RESTRICTION_NONE
+ && !mSuspendPackageHelper.isSuspendAllowedForUser(snapshot, userId, callingUid)) {
+ Slog.w(PackageManagerService.TAG,
+ "Cannot restrict packages due to restrictions on user " + userId);
+ return packageNames;
+ }
+
+ final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
+ final IntArray changedUids = new IntArray(packageNames.length);
+ final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
+
+ final ArraySet<String> changesToCommit = new ArraySet<>();
+ final boolean[] canRestrict = (restrictionFlags != RESTRICTION_NONE)
+ ? mSuspendPackageHelper.canSuspendPackageForUser(snapshot, packageNames, userId,
+ callingUid) : null;
+ for (int i = 0; i < packageNames.length; i++) {
+ final String packageName = packageNames[i];
+ final PackageStateInternal packageState =
+ snapshot.getPackageStateInternal(packageName);
+ if (packageState == null
+ || snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
+ Slog.w(PackageManagerService.TAG,
+ "Could not find package setting for package: " + packageName
+ + ". Skipping...");
+ unactionedPackages.add(packageName);
+ continue;
+ }
+ if (canRestrict != null && !canRestrict[i]) {
+ unactionedPackages.add(packageName);
+ continue;
+ }
+ final int oldDistractionFlags = packageState.getUserStateOrDefault(userId)
+ .getDistractionFlags();
+ if (restrictionFlags != oldDistractionFlags) {
+ changedPackagesList.add(packageName);
+ changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+ changesToCommit.add(packageName);
+ }
+ }
+
+ mPm.commitPackageStateMutation(null /* initialState */, mutator -> {
+ final int size = changesToCommit.size();
+ for (int index = 0; index < size; index++) {
+ mutator.forPackage(changesToCommit.valueAt(index))
+ .userState(userId)
+ .setDistractionFlags(restrictionFlags);
+ }
+ });
+
+ if (!changedPackagesList.isEmpty()) {
+ final String[] changedPackages = changedPackagesList.toArray(
+ new String[changedPackagesList.size()]);
+ sendDistractingPackagesChanged(changedPackages, changedUids.toArray(), userId,
+ restrictionFlags);
+ mPm.scheduleWritePackageRestrictions(userId);
+ }
+ return unactionedPackages.toArray(new String[0]);
+ }
+
+ /**
+ * Removes any {@link DistractionRestriction restrictions} set on given packages.
+ *
+ * <p> Caller must flush package restrictions if it cares about immediate data consistency.
+ *
+ * @param packagesToChange The packages on which restrictions are to be removed.
+ * @param userId the user for which changes are taking place.
+ */
+ void removeDistractingPackageRestrictions(@NonNull Computer snapshot,
+ String[] packagesToChange, int userId) {
+ if (ArrayUtils.isEmpty(packagesToChange)) {
+ return;
+ }
+ final List<String> changedPackages = new ArrayList<>(packagesToChange.length);
+ final IntArray changedUids = new IntArray(packagesToChange.length);
+ for (int i = 0; i < packagesToChange.length; i++) {
+ final String packageName = packagesToChange[i];
+ final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName);
+ if (ps != null && ps.getUserStateOrDefault(userId).getDistractionFlags()
+ != RESTRICTION_NONE) {
+ changedPackages.add(ps.getPackageName());
+ changedUids.add(UserHandle.getUid(userId, ps.getAppId()));
+ }
+ }
+ mPm.commitPackageStateMutation(null /* initialState */, mutator -> {
+ for (int index = 0; index < changedPackages.size(); index++) {
+ mutator.forPackage(changedPackages.get(index))
+ .userState(userId)
+ .setDistractionFlags(RESTRICTION_NONE);
+ }
+ });
+
+ if (!changedPackages.isEmpty()) {
+ final String[] packageArray = changedPackages.toArray(
+ new String[changedPackages.size()]);
+ sendDistractingPackagesChanged(packageArray, changedUids.toArray(), userId,
+ RESTRICTION_NONE);
+ mPm.scheduleWritePackageRestrictions(userId);
+ }
+ }
+
+ /**
+ * Send broadcast intents for packages distracting changes.
+ *
+ * @param pkgList The names of packages which have suspension changes.
+ * @param uidList The uids of packages which have suspension changes.
+ * @param userId The user where packages reside.
+ */
+ void sendDistractingPackagesChanged(@NonNull String[] pkgList,
+ int[] uidList, int userId, int distractionFlags) {
+ final Bundle extras = new Bundle(3);
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList);
+ extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, distractionFlags);
+
+ final Handler handler = mInjector.getHandler();
+ handler.post(() -> mBroadcastHelper.sendPackageBroadcast(
+ Intent.ACTION_DISTRACTING_PACKAGES_CHANGED, null /* pkg */, extras,
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY, null /* targetPkg */,
+ null /* finishedReceiver */, new int[]{userId}, null /* instantUserIds */,
+ null /* allowList */, null /* bOptions */));
+ }
+}
diff --git a/services/core/java/com/android/server/pm/DumpHelper.java b/services/core/java/com/android/server/pm/DumpHelper.java
index f83ef5aea23a..276644036def 100644
--- a/services/core/java/com/android/server/pm/DumpHelper.java
+++ b/services/core/java/com/android/server/pm/DumpHelper.java
@@ -17,45 +17,76 @@
package com.android.server.pm;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
-import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE;
+import static com.android.server.pm.KnownPackages.LAST_KNOWN_PACKAGE;
import static com.android.server.pm.PackageManagerServiceUtils.dumpCriticalInfo;
+import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.UserHandle;
import android.os.incremental.PerUidReadTimeouts;
import android.service.pm.PackageServiceDumpProto;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.resolution.ComponentResolverApi;
+import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
import dalvik.annotation.optimization.NeverCompile;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.function.BiConsumer;
/**
* Dumps PackageManagerService internal states.
*/
final class DumpHelper {
- final PackageManagerService mPm;
-
- DumpHelper(PackageManagerService pm) {
- mPm = pm;
+ private final PermissionManagerServiceInternal mPermissionManager;
+ private final ApexManager mApexManager;
+ private final StorageEventHelper mStorageEventHelper;
+ private final DomainVerificationManagerInternal mDomainVerificationManager;
+ private final PackageInstallerService mInstallerService;
+ private final String mRequiredVerifierPackage;
+ private final KnownPackages mKnownPackages;
+ private final ChangedPackagesTracker mChangedPackagesTracker;
+ private final ArrayMap<String, FeatureInfo> mAvailableFeatures;
+ private final ArraySet<String> mProtectedBroadcasts;
+ private final PerUidReadTimeouts[] mPerUidReadTimeouts;
+
+ DumpHelper(
+ PermissionManagerServiceInternal permissionManager, ApexManager apexManager,
+ StorageEventHelper storageEventHelper,
+ DomainVerificationManagerInternal domainVerificationManager,
+ PackageInstallerService installerService, String requiredVerifierPackage,
+ KnownPackages knownPackages,
+ ChangedPackagesTracker changedPackagesTracker,
+ ArrayMap<String, FeatureInfo> availableFeatures,
+ ArraySet<String> protectedBroadcasts,
+ PerUidReadTimeouts[] perUidReadTimeouts) {
+ mPermissionManager = permissionManager;
+ mApexManager = apexManager;
+ mStorageEventHelper = storageEventHelper;
+ mDomainVerificationManager = domainVerificationManager;
+ mInstallerService = installerService;
+ mRequiredVerifierPackage = requiredVerifierPackage;
+ mKnownPackages = knownPackages;
+ mChangedPackagesTracker = changedPackagesTracker;
+ mAvailableFeatures = availableFeatures;
+ mProtectedBroadcasts = protectedBroadcasts;
+ mPerUidReadTimeouts = perUidReadTimeouts;
}
@NeverCompile // Avoid size overhead of debugging code.
- public void doDump(FileDescriptor fd, PrintWriter pw, String[] args) {
- final Computer snapshot = mPm.snapshotComputer();
+ public void doDump(Computer snapshot, FileDescriptor fd, PrintWriter pw, String[] args) {
DumpState dumpState = new DumpState();
ArraySet<String> permissionNames = null;
@@ -79,7 +110,7 @@ final class DumpHelper {
} else if ("-f".equals(opt)) {
dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS);
} else if ("--proto".equals(opt)) {
- dumpProto(fd);
+ dumpProto(snapshot, fd);
return;
} else {
pw.println("Unknown argument: " + opt + "; use -h for help");
@@ -122,9 +153,10 @@ final class DumpHelper {
}
// Normalize package name to handle renamed packages and static libs
- pkg = snapshot.resolveInternalPackageName(pkg, PackageManager.VERSION_CODE_HIGHEST);
+ pkg = snapshot.resolveInternalPackageName(pkg,
+ PackageManager.VERSION_CODE_HIGHEST);
- pw.println(mPm.checkPermission(perm, pkg, user));
+ pw.println(mPermissionManager.checkPermission(perm, pkg, user));
return;
} else if ("l".equals(cmd) || "libraries".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_LIBS);
@@ -230,12 +262,6 @@ final class DumpHelper {
}
} else if ("protected-broadcasts".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_PROTECTED_BROADCASTS);
- } else if ("write".equals(cmd)) {
- synchronized (mPm.mLock) {
- mPm.writeSettingsLPrTEMP();
- pw.println("Settings written.");
- return;
- }
}
}
@@ -245,7 +271,7 @@ final class DumpHelper {
// Return if the package doesn't exist.
if (packageName != null
&& snapshot.getPackageStateInternal(packageName) == null
- && !mPm.mApexManager.isApexPackage(packageName)) {
+ && !mApexManager.isApexPackage(packageName)) {
pw.println("Unable to find package: " + packageName);
return;
}
@@ -271,11 +297,11 @@ final class DumpHelper {
ipw.println("Known Packages:");
ipw.increaseIndent();
for (int i = 0; i <= LAST_KNOWN_PACKAGE; i++) {
- final String knownPackage = PackageManagerInternal.knownPackageToString(i);
+ final String knownPackage = KnownPackages.knownPackageToString(i);
ipw.print(knownPackage);
ipw.println(":");
- final String[] pkgNames = mPm.getKnownPackageNamesInternal(snapshot, i,
- UserHandle.USER_SYSTEM);
+ final String[] pkgNames = mKnownPackages.getKnownPackageNames(snapshot,
+ i, UserHandle.USER_SYSTEM);
ipw.increaseIndent();
if (ArrayUtils.isEmpty(pkgNames)) {
ipw.println("none");
@@ -291,7 +317,7 @@ final class DumpHelper {
if (dumpState.isDumping(DumpState.DUMP_VERIFIERS)
&& packageName == null) {
- final String requiredVerifierPackage = mPm.mRequiredVerifierPackage;
+ final String requiredVerifierPackage = mRequiredVerifierPackage;
if (!checkin) {
if (dumpState.onTitlePrinted()) {
pw.println();
@@ -304,7 +330,8 @@ final class DumpHelper {
MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM));
pw.println(")");
} else if (requiredVerifierPackage != null) {
- pw.print("vrfy,"); pw.print(requiredVerifierPackage);
+ pw.print("vrfy,");
+ pw.print(requiredVerifierPackage);
pw.print(",");
pw.println(snapshot.getPackageUid(requiredVerifierPackage,
MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM));
@@ -313,7 +340,7 @@ final class DumpHelper {
if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER)
&& packageName == null) {
- final DomainVerificationProxy proxy = mPm.mDomainVerificationManager.getProxy();
+ final DomainVerificationProxy proxy = mDomainVerificationManager.getProxy();
final ComponentName verifierComponent = proxy.getComponentName();
if (verifierComponent != null) {
String verifierPackageName = verifierComponent.getPackageName();
@@ -329,7 +356,8 @@ final class DumpHelper {
MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM));
pw.println(")");
} else if (verifierPackageName != null) {
- pw.print("dv,"); pw.print(verifierPackageName);
+ pw.print("dv,");
+ pw.print(verifierPackageName);
pw.print(",");
pw.println(snapshot.getPackageUid(verifierPackageName,
MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM));
@@ -354,76 +382,75 @@ final class DumpHelper {
pw.println("Features:");
}
- synchronized (mPm.mAvailableFeatures) {
- for (FeatureInfo feat : mPm.mAvailableFeatures.values()) {
- if (!checkin) {
- pw.print(" ");
- pw.print(feat.name);
- if (feat.version > 0) {
- pw.print(" version=");
- pw.print(feat.version);
- }
- pw.println();
- } else {
- pw.print("feat,");
- pw.print(feat.name);
- pw.print(",");
- pw.println(feat.version);
+ for (FeatureInfo feat : mAvailableFeatures.values()) {
+ if (!checkin) {
+ pw.print(" ");
+ pw.print(feat.name);
+ if (feat.version > 0) {
+ pw.print(" version=");
+ pw.print(feat.version);
}
+ pw.println();
+ } else {
+ pw.print("feat,");
+ pw.print(feat.name);
+ pw.print(",");
+ pw.println(feat.version);
}
}
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) {
- mPm.mComponentResolver.dumpActivityResolvers(pw, dumpState, packageName);
+ final ComponentResolverApi componentResolver = snapshot.getComponentResolver();
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) {
+ componentResolver.dumpActivityResolvers(pw, dumpState, packageName);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) {
- mPm.mComponentResolver.dumpReceiverResolvers(pw, dumpState, packageName);
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) {
+ componentResolver.dumpReceiverResolvers(pw, dumpState, packageName);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) {
- mPm.mComponentResolver.dumpServiceResolvers(pw, dumpState, packageName);
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) {
+ componentResolver.dumpServiceResolvers(pw, dumpState, packageName);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) {
- mPm.mComponentResolver.dumpProviderResolvers(pw, dumpState, packageName);
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) {
+ componentResolver.dumpProviderResolvers(pw, dumpState, packageName);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
snapshot.dump(DumpState.DUMP_PREFERRED, fd, pw, dumpState);
}
if (!checkin
- && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)
- && packageName == null) {
+ && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML) && packageName == null) {
snapshot.dump(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
snapshot.dump(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
- mPm.mSettings.dumpPermissions(pw, packageName, permissionNames, dumpState);
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
+ snapshot.dumpPermissions(pw, packageName, permissionNames, dumpState);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
- mPm.mComponentResolver.dumpContentProviders(snapshot, pw, dumpState,
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
+ componentResolver.dumpContentProviders(snapshot, pw, dumpState,
packageName);
}
if (!checkin
&& dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
- synchronized (mPm.mLock) {
- mPm.mSettings.getKeySetManagerService().dumpLPr(pw, packageName, dumpState);
- }
+ snapshot.dumpKeySet(pw, packageName, dumpState);
}
if (dumpState.isDumping(DumpState.DUMP_PACKAGES)) {
- // This cannot be moved to ComputerEngine since some variables of the collections
- // in PackageUserState such as suspendParams, disabledComponents and enabledComponents
- // do not have a copy.
- synchronized (mPm.mLock) {
- mPm.mSettings.dumpPackagesLPr(pw, packageName, permissionNames, dumpState, checkin);
- }
+ snapshot.dumpPackages(pw, packageName, permissionNames, dumpState, checkin);
}
if (!checkin
@@ -432,12 +459,8 @@ final class DumpHelper {
}
if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) {
- // This cannot be moved to ComputerEngine since the set of packages in the
- // SharedUserSetting do not have a copy.
- synchronized (mPm.mLock) {
- mPm.mSettings.dumpSharedUsersLPr(pw, packageName, permissionNames, dumpState,
- checkin);
- }
+ snapshot.dumpSharedUsers(pw, packageName, permissionNames, dumpState,
+ checkin);
}
if (!checkin
@@ -447,15 +470,19 @@ final class DumpHelper {
pw.println();
}
pw.println("Package Changes:");
- mPm.mChangedPackagesTracker.iterateAll((sequenceNumber, values) -> {
- pw.print(" Sequence number="); pw.println(sequenceNumber);
+ mChangedPackagesTracker.iterateAll((sequenceNumber, values) -> {
+ pw.print(" Sequence number=");
+ pw.println(sequenceNumber);
final int numChangedPackages = values.size();
for (int i = 0; i < numChangedPackages; i++) {
final SparseArray<String> changes = values.valueAt(i);
- pw.print(" User "); pw.print(values.keyAt(i)); pw.println(":");
+ pw.print(" User ");
+ pw.print(values.keyAt(i));
+ pw.println(":");
final int numChanges = changes.size();
if (numChanges == 0) {
- pw.print(" "); pw.println("No packages changed");
+ pw.print(" ");
+ pw.println("No packages changed");
} else {
for (int j = 0; j < numChanges; j++) {
final String pkgName = changes.valueAt(j);
@@ -474,56 +501,19 @@ final class DumpHelper {
if (!checkin
&& dumpState.isDumping(DumpState.DUMP_FROZEN)
&& packageName == null) {
- // XXX should handle packageName != null by dumping only install data that
- // the given package is involved with.
- if (dumpState.onTitlePrinted()) {
- pw.println();
- }
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
- ipw.println();
- ipw.println("Frozen packages:");
- ipw.increaseIndent();
- synchronized (mPm.mLock) {
- if (mPm.mFrozenPackages.size() == 0) {
- ipw.println("(none)");
- } else {
- for (int i = 0; i < mPm.mFrozenPackages.size(); i++) {
- ipw.print("package=");
- ipw.print(mPm.mFrozenPackages.keyAt(i));
- ipw.print(", refCounts=");
- ipw.println(mPm.mFrozenPackages.valueAt(i));
- }
- }
- }
- ipw.decreaseIndent();
+ snapshot.dump(DumpState.DUMP_FROZEN, fd, pw, dumpState);
}
if (!checkin
&& dumpState.isDumping(DumpState.DUMP_VOLUMES)
&& packageName == null) {
- if (dumpState.onTitlePrinted()) {
- pw.println();
- }
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
- ipw.println();
- ipw.println("Loaded volumes:");
- ipw.increaseIndent();
- synchronized (mPm.mLoadedVolumes) {
- if (mPm.mLoadedVolumes.size() == 0) {
- ipw.println("(none)");
- } else {
- for (int i = 0; i < mPm.mLoadedVolumes.size(); i++) {
- ipw.println(mPm.mLoadedVolumes.valueAt(i));
- }
- }
- }
- ipw.decreaseIndent();
+ mStorageEventHelper.dumpLoadedVolumes(pw, dumpState);
}
if (!checkin
&& dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
&& packageName == null) {
- mPm.mComponentResolver.dumpServicePermissions(pw, dumpState);
+ componentResolver.dumpServicePermissions(pw, dumpState);
}
if (!checkin
@@ -542,7 +532,7 @@ final class DumpHelper {
if (dumpState.onTitlePrinted()) {
pw.println();
}
- mPm.mSettings.dumpReadMessages(pw, dumpState);
+ snapshot.dump(DumpState.DUMP_MESSAGES, fd, pw, dumpState);
pw.println();
pw.println("Package warning messages:");
dumpCriticalInfo(pw, null);
@@ -560,13 +550,13 @@ final class DumpHelper {
if (dumpState.onTitlePrinted()) {
pw.println();
}
- mPm.mInstallerService.dump(new IndentingPrintWriter(pw, " ", 120));
+ mInstallerService.dump(new IndentingPrintWriter(pw, " ", 120));
}
if (!checkin
&& dumpState.isDumping(DumpState.DUMP_APEX)
- && (packageName == null || mPm.mApexManager.isApexPackage(packageName))) {
- mPm.mApexManager.dump(pw, packageName);
+ && (packageName == null || mApexManager.isApexPackage(packageName))) {
+ mApexManager.dump(pw, packageName);
}
if (!checkin
@@ -580,9 +570,8 @@ final class DumpHelper {
pw.println(" Known digesters list flag: "
+ PackageManagerService.getKnownDigestersList());
- PerUidReadTimeouts[] items = mPm.getPerUidReadTimeouts(snapshot);
- pw.println(" Timeouts (" + items.length + "):");
- for (PerUidReadTimeouts item : items) {
+ pw.println(" Timeouts (" + mPerUidReadTimeouts.length + "):");
+ for (PerUidReadTimeouts item : mPerUidReadTimeouts) {
pw.print(" (");
pw.print("uid=" + item.uid + ", ");
pw.print("minTimeUs=" + item.minTimeUs + ", ");
@@ -598,8 +587,6 @@ final class DumpHelper {
if (dumpState.onTitlePrinted()) {
pw.println();
}
- pw.println("Snapshot statistics");
- mPm.dumpSnapshotStats(pw, dumpState.isBrief());
}
if (!checkin
@@ -609,11 +596,9 @@ final class DumpHelper {
pw.println();
}
pw.println("Protected broadcast actions:");
- synchronized (mPm.mProtectedBroadcasts) {
- for (int i = 0; i < mPm.mProtectedBroadcasts.size(); i++) {
- pw.print(" ");
- pw.println(mPm.mProtectedBroadcasts.valueAt(i));
- }
+ for (int i = 0; i < mProtectedBroadcasts.size(); i++) {
+ pw.print(" ");
+ pw.println(mProtectedBroadcasts.valueAt(i));
}
}
@@ -658,55 +643,50 @@ final class DumpHelper {
pw.println(" <package.name>: info about given package");
}
- private void dumpProto(FileDescriptor fd) {
+ private void dumpProto(Computer snapshot, FileDescriptor fd) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
- synchronized (mPm.mLock) {
- final Computer snapshot = mPm.snapshotComputer();
- final long requiredVerifierPackageToken =
- proto.start(PackageServiceDumpProto.REQUIRED_VERIFIER_PACKAGE);
- proto.write(PackageServiceDumpProto.PackageShortProto.NAME,
- mPm.mRequiredVerifierPackage);
+ final long requiredVerifierPackageToken =
+ proto.start(PackageServiceDumpProto.REQUIRED_VERIFIER_PACKAGE);
+ proto.write(PackageServiceDumpProto.PackageShortProto.NAME,
+ mRequiredVerifierPackage);
+ proto.write(
+ PackageServiceDumpProto.PackageShortProto.UID,
+ snapshot.getPackageUid(
+ mRequiredVerifierPackage,
+ MATCH_DEBUG_TRIAGED_MISSING,
+ UserHandle.USER_SYSTEM));
+ proto.end(requiredVerifierPackageToken);
+
+ DomainVerificationProxy proxy = mDomainVerificationManager.getProxy();
+ ComponentName verifierComponent = proxy.getComponentName();
+ if (verifierComponent != null) {
+ String verifierPackageName = verifierComponent.getPackageName();
+ final long verifierPackageToken =
+ proto.start(PackageServiceDumpProto.VERIFIER_PACKAGE);
+ proto.write(PackageServiceDumpProto.PackageShortProto.NAME, verifierPackageName);
proto.write(
PackageServiceDumpProto.PackageShortProto.UID,
snapshot.getPackageUid(
- mPm.mRequiredVerifierPackage,
+ verifierPackageName,
MATCH_DEBUG_TRIAGED_MISSING,
UserHandle.USER_SYSTEM));
- proto.end(requiredVerifierPackageToken);
-
- DomainVerificationProxy proxy = mPm.mDomainVerificationManager.getProxy();
- ComponentName verifierComponent = proxy.getComponentName();
- if (verifierComponent != null) {
- String verifierPackageName = verifierComponent.getPackageName();
- final long verifierPackageToken =
- proto.start(PackageServiceDumpProto.VERIFIER_PACKAGE);
- proto.write(PackageServiceDumpProto.PackageShortProto.NAME, verifierPackageName);
- proto.write(
- PackageServiceDumpProto.PackageShortProto.UID,
- snapshot.getPackageUid(
- verifierPackageName,
- MATCH_DEBUG_TRIAGED_MISSING,
- UserHandle.USER_SYSTEM));
- proto.end(verifierPackageToken);
- }
-
- mPm.mInjector.getSharedLibrariesImpl().dumpProto(proto);
- dumpFeaturesProto(proto);
- mPm.mSettings.dumpPackagesProto(proto);
- mPm.mSettings.dumpSharedUsersProto(proto);
- dumpCriticalInfo(proto);
+ proto.end(verifierPackageToken);
}
+
+ snapshot.dumpSharedLibrariesProto(proto);
+ dumpAvailableFeaturesProto(proto);
+ snapshot.dumpPackagesProto(proto);
+ snapshot.dumpSharedUsersProto(proto);
+ dumpCriticalInfo(proto);
proto.flush();
}
- private void dumpFeaturesProto(ProtoOutputStream proto) {
- synchronized (mPm.mAvailableFeatures) {
- final int count = mPm.mAvailableFeatures.size();
- for (int i = 0; i < count; i++) {
- mPm.mAvailableFeatures.valueAt(i).dumpDebug(proto,
- PackageServiceDumpProto.FEATURES);
- }
+
+ private void dumpAvailableFeaturesProto(@NonNull ProtoOutputStream proto) {
+ final int count = mAvailableFeatures.size();
+ for (int i = 0; i < count; i++) {
+ mAvailableFeatures.valueAt(i).dumpDebug(proto, PackageServiceDumpProto.FEATURES);
}
}
}
diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java
index e1aee6d747f4..ba7309f0283d 100644
--- a/services/core/java/com/android/server/pm/IPackageManagerBase.java
+++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java
@@ -803,7 +803,7 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub {
public final String getSystemCaptionsServicePackageName() {
return mService.ensureSystemPackageName(snapshot(),
mService.getPackageFromComponentString(
- R.string.config_defaultSystemCaptionsService));
+ R.string.config_defaultSystemCaptionsManagerService));
}
@Nullable
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 870a11ac2d61..77d37dc377a2 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -427,7 +427,7 @@ final class InstallPackageHelper {
} else {
// We're doing major surgery on this package, so it better be frozen
// right now to keep it from launching
- mPm.checkPackageFrozen(pkgName);
+ mPm.snapshotComputer().checkPackageFrozen(pkgName);
}
final boolean isReplace =
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index fff66629048d..2a66e026438a 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -287,6 +287,9 @@ public class Installer extends SystemService {
* Sets in Installd that it is first boot after data wipe
*/
public void setFirstBoot() throws InstallerException {
+ if (!checkBeforeRemote()) {
+ return;
+ }
try {
mInstalld.setFirstBoot();
} catch (RemoteException e) {
@@ -689,6 +692,20 @@ public class Installer extends SystemService {
}
}
+ /**
+ * Deletes the reference profile with the given name of the given package.
+ * @throws InstallerException if the deletion fails.
+ */
+ public void deleteReferenceProfile(String packageName, String profileName)
+ throws InstallerException {
+ if (!checkBeforeRemote()) return;
+ try {
+ mInstalld.deleteReferenceProfile(packageName, profileName);
+ } catch (Exception e) {
+ throw InstallerException.from(e);
+ }
+ }
+
public void createUserData(String uuid, int userId, int userSerial, int flags)
throws InstallerException {
if (!checkBeforeRemote()) return;
diff --git a/services/core/java/com/android/server/pm/IntentResolverInterceptor.java b/services/core/java/com/android/server/pm/IntentResolverInterceptor.java
index 5597c9af7362..603badb276b2 100644
--- a/services/core/java/com/android/server/pm/IntentResolverInterceptor.java
+++ b/services/core/java/com/android/server/pm/IntentResolverInterceptor.java
@@ -81,7 +81,7 @@ public final class IntentResolverInterceptor {
private void updateUseDelegateChooser() {
mUseDelegateChooser = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.USE_DELEGATE_CHOOSER,
+ SystemUiDeviceConfigFlags.USE_UNBUNDLED_SHARESHEET,
false);
}
diff --git a/services/core/java/com/android/server/pm/KnownPackages.java b/services/core/java/com/android/server/pm/KnownPackages.java
new file mode 100644
index 000000000000..04376b448e32
--- /dev/null
+++ b/services/core/java/com/android/server/pm/KnownPackages.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.text.TextUtils;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Helps {@link PackageManagerService} keep track of the names of special packages like SetupWizard.
+ */
+public final class KnownPackages {
+ @IntDef(prefix = "PACKAGE_", value = {
+ PACKAGE_SYSTEM,
+ PACKAGE_SETUP_WIZARD,
+ PACKAGE_INSTALLER,
+ PACKAGE_UNINSTALLER,
+ PACKAGE_VERIFIER,
+ PACKAGE_BROWSER,
+ PACKAGE_SYSTEM_TEXT_CLASSIFIER,
+ PACKAGE_PERMISSION_CONTROLLER,
+ PACKAGE_CONFIGURATOR,
+ PACKAGE_INCIDENT_REPORT_APPROVER,
+ PACKAGE_APP_PREDICTOR,
+ PACKAGE_OVERLAY_CONFIG_SIGNATURE,
+ PACKAGE_WIFI,
+ PACKAGE_COMPANION,
+ PACKAGE_RETAIL_DEMO,
+ PACKAGE_RECENTS,
+ PACKAGE_AMBIENT_CONTEXT_DETECTION,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface KnownPackage {
+ }
+
+ public static final int PACKAGE_SYSTEM = 0;
+ public static final int PACKAGE_SETUP_WIZARD = 1;
+ public static final int PACKAGE_INSTALLER = 2;
+ public static final int PACKAGE_UNINSTALLER = 3;
+ public static final int PACKAGE_VERIFIER = 4;
+ public static final int PACKAGE_BROWSER = 5;
+ public static final int PACKAGE_SYSTEM_TEXT_CLASSIFIER = 6;
+ public static final int PACKAGE_PERMISSION_CONTROLLER = 7;
+ public static final int PACKAGE_WELLBEING = 8;
+ public static final int PACKAGE_DOCUMENTER = 9;
+ public static final int PACKAGE_CONFIGURATOR = 10;
+ public static final int PACKAGE_INCIDENT_REPORT_APPROVER = 11;
+ public static final int PACKAGE_APP_PREDICTOR = 12;
+ public static final int PACKAGE_OVERLAY_CONFIG_SIGNATURE = 13;
+ public static final int PACKAGE_WIFI = 14;
+ public static final int PACKAGE_COMPANION = 15;
+ public static final int PACKAGE_RETAIL_DEMO = 16;
+ public static final int PACKAGE_RECENTS = 17;
+ public static final int PACKAGE_AMBIENT_CONTEXT_DETECTION = 18;
+ // Integer value of the last known package ID. Increases as new ID is added to KnownPackage.
+ // Please note the numbers should be continuous.
+ public static final int LAST_KNOWN_PACKAGE = PACKAGE_AMBIENT_CONTEXT_DETECTION;
+
+ private final DefaultAppProvider mDefaultAppProvider;
+ private final String mRequiredInstallerPackage;
+ private final String mRequiredUninstallerPackage;
+ private final String mSetupWizardPackage;
+ private final String mRequiredVerifierPackage;
+ private final String mDefaultTextClassifierPackage;
+ private final String mSystemTextClassifierPackageName;
+ private final String mRequiredPermissionControllerPackage;
+ private final String mConfiguratorPackage;
+ private final String mIncidentReportApproverPackage;
+ private final String mAmbientContextDetectionPackage;
+ private final String mAppPredictionServicePackage;
+ private final String mCompanionPackage;
+ private final String mRetailDemoPackage;
+ private final String mOverlayConfigSignaturePackage;
+ private final String mRecentsPackage;
+
+ KnownPackages(DefaultAppProvider defaultAppProvider, String requiredInstallerPackage,
+ String requiredUninstallerPackage, String setupWizardPackage,
+ String requiredVerifierPackage, String defaultTextClassifierPackage,
+ String systemTextClassifierPackageName, String requiredPermissionControllerPackage,
+ String configuratorPackage, String incidentReportApproverPackage,
+ String ambientContextDetectionPackage, String appPredictionServicePackage,
+ String companionPackageName, String retailDemoPackage,
+ String overlayConfigSignaturePackage, String recentsPackage) {
+ mDefaultAppProvider = defaultAppProvider;
+ mRequiredInstallerPackage = requiredInstallerPackage;
+ mRequiredUninstallerPackage = requiredUninstallerPackage;
+ mSetupWizardPackage = setupWizardPackage;
+ mRequiredVerifierPackage = requiredVerifierPackage;
+ mDefaultTextClassifierPackage = defaultTextClassifierPackage;
+ mSystemTextClassifierPackageName = systemTextClassifierPackageName;
+ mRequiredPermissionControllerPackage = requiredPermissionControllerPackage;
+ mConfiguratorPackage = configuratorPackage;
+ mIncidentReportApproverPackage = incidentReportApproverPackage;
+ mAmbientContextDetectionPackage = ambientContextDetectionPackage;
+ mAppPredictionServicePackage = appPredictionServicePackage;
+ mCompanionPackage = companionPackageName;
+ mRetailDemoPackage = retailDemoPackage;
+ mOverlayConfigSignaturePackage = overlayConfigSignaturePackage;
+ mRecentsPackage = recentsPackage;
+ }
+
+ /**
+ * Returns the string representation of a known package. For example,
+ * {@link #PACKAGE_SETUP_WIZARD} is represented by the string Setup Wizard.
+ *
+ * @param knownPackage The known package.
+ * @return The string representation.
+ */
+ static @NonNull String knownPackageToString(@KnownPackage int knownPackage) {
+ switch (knownPackage) {
+ case PACKAGE_SYSTEM:
+ return "System";
+ case PACKAGE_SETUP_WIZARD:
+ return "Setup Wizard";
+ case PACKAGE_INSTALLER:
+ return "Installer";
+ case PACKAGE_UNINSTALLER:
+ return "Uninstaller";
+ case PACKAGE_VERIFIER:
+ return "Verifier";
+ case PACKAGE_BROWSER:
+ return "Browser";
+ case PACKAGE_SYSTEM_TEXT_CLASSIFIER:
+ return "System Text Classifier";
+ case PACKAGE_PERMISSION_CONTROLLER:
+ return "Permission Controller";
+ case PACKAGE_WELLBEING:
+ return "Wellbeing";
+ case PACKAGE_DOCUMENTER:
+ return "Documenter";
+ case PACKAGE_CONFIGURATOR:
+ return "Configurator";
+ case PACKAGE_INCIDENT_REPORT_APPROVER:
+ return "Incident Report Approver";
+ case PACKAGE_APP_PREDICTOR:
+ return "App Predictor";
+ case PACKAGE_WIFI:
+ return "Wi-Fi";
+ case PACKAGE_COMPANION:
+ return "Companion";
+ case PACKAGE_RETAIL_DEMO:
+ return "Retail Demo";
+ case PACKAGE_OVERLAY_CONFIG_SIGNATURE:
+ return "Overlay Config Signature";
+ case PACKAGE_RECENTS:
+ return "Recents";
+ case PACKAGE_AMBIENT_CONTEXT_DETECTION:
+ return "Ambient Context Detection";
+ }
+ return "Unknown";
+ }
+
+ String[] getKnownPackageNames(@NonNull Computer snapshot, int knownPackage, int userId) {
+ switch (knownPackage) {
+ case PACKAGE_BROWSER:
+ return new String[]{mDefaultAppProvider.getDefaultBrowser(userId)};
+ case PACKAGE_INSTALLER:
+ return snapshot.filterOnlySystemPackages(mRequiredInstallerPackage);
+ case PACKAGE_UNINSTALLER:
+ return snapshot.filterOnlySystemPackages(mRequiredUninstallerPackage);
+ case PACKAGE_SETUP_WIZARD:
+ return snapshot.filterOnlySystemPackages(mSetupWizardPackage);
+ case PACKAGE_SYSTEM:
+ return new String[]{"android"};
+ case PACKAGE_VERIFIER:
+ return snapshot.filterOnlySystemPackages(mRequiredVerifierPackage);
+ case PACKAGE_SYSTEM_TEXT_CLASSIFIER:
+ return snapshot.filterOnlySystemPackages(
+ mDefaultTextClassifierPackage, mSystemTextClassifierPackageName);
+ case PACKAGE_PERMISSION_CONTROLLER:
+ return snapshot.filterOnlySystemPackages(mRequiredPermissionControllerPackage);
+ case PACKAGE_CONFIGURATOR:
+ return snapshot.filterOnlySystemPackages(mConfiguratorPackage);
+ case PACKAGE_INCIDENT_REPORT_APPROVER:
+ return snapshot.filterOnlySystemPackages(mIncidentReportApproverPackage);
+ case PACKAGE_AMBIENT_CONTEXT_DETECTION:
+ return snapshot.filterOnlySystemPackages(mAmbientContextDetectionPackage);
+ case PACKAGE_APP_PREDICTOR:
+ return snapshot.filterOnlySystemPackages(mAppPredictionServicePackage);
+ case PACKAGE_COMPANION:
+ return snapshot.filterOnlySystemPackages(mCompanionPackage);
+ case PACKAGE_RETAIL_DEMO:
+ return TextUtils.isEmpty(mRetailDemoPackage)
+ ? ArrayUtils.emptyArray(String.class)
+ : new String[]{mRetailDemoPackage};
+ case PACKAGE_OVERLAY_CONFIG_SIGNATURE:
+ return snapshot.filterOnlySystemPackages(mOverlayConfigSignaturePackage);
+ case PACKAGE_RECENTS:
+ return snapshot.filterOnlySystemPackages(mRecentsPackage);
+ default:
+ return ArrayUtils.emptyArray(String.class);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 27c6d9bec2e8..af0a20ddf337 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -324,12 +324,12 @@ public class PackageDexOptimizer {
String compilerFilter = getRealCompilerFilter(pkg, options.getCompilerFilter());
// If the app is used by other apps, we must not use the existing profile because it
// may contain user data, unless the profile is newly created on install.
- final boolean resetProfile = isProfileGuidedCompilerFilter(compilerFilter)
+ final boolean useCloudProfile = isProfileGuidedCompilerFilter(compilerFilter)
&& isUsedByOtherApps
&& options.getCompilationReason() != PackageManagerService.REASON_INSTALL;
String dexMetadataPath = null;
- if (options.isDexoptInstallWithDexMetadata() || resetProfile) {
+ if (options.isDexoptInstallWithDexMetadata() || useCloudProfile) {
File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(new File(path));
dexMetadataPath = dexMetadataFile == null
? null : dexMetadataFile.getAbsolutePath();
@@ -339,65 +339,87 @@ public class PackageDexOptimizer {
// PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA which will be a no-op with respect to
// profiles.
int profileAnalysisResult = PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
- if (resetProfile) {
- if (!resetProfile(pkg, profileName, path, dexMetadataPath)) {
- // Fall back to use the shared filter.
- compilerFilter =
- PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
- PackageManagerService.REASON_SHARED);
- }
- } else if (options.isCheckForProfileUpdates()) {
+ if (options.isCheckForProfileUpdates()) {
profileAnalysisResult =
analyseProfiles(pkg, sharedGid, profileName, compilerFilter);
}
-
- // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct
- // flags.
- final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, resetProfile,
- options);
-
- for (String dexCodeIsa : dexCodeInstructionSets) {
- int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter,
- profileAnalysisResult, classLoaderContexts[i], dexoptFlags, sharedGid,
- packageStats, options.isDowngrade(), profileName, dexMetadataPath,
- options.getCompilationReason());
- // OTAPreopt doesn't have stats so don't report in that case.
- if (packageStats != null) {
- Trace.traceBegin(Trace.TRACE_TAG_PACKAGE_MANAGER, "dex2oat-metrics");
- try {
- long sessionId = sRandom.nextLong();
- ArtStatsLogUtils.writeStatsLog(
- mArtStatsLogger,
- sessionId,
- compilerFilter,
- pkg.getUid(),
- packageStats.getCompileTime(path),
- dexMetadataPath,
- options.getCompilationReason(),
- newResult,
- ArtStatsLogUtils.getApkType(path, pkg.getBaseApkPath(),
- pkg.getSplitCodePaths()),
- dexCodeIsa,
- path);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_PACKAGE_MANAGER);
+ String cloudProfileName = null;
+ try {
+ if (useCloudProfile) {
+ cloudProfileName = "cloud-" + profileName;
+ if (prepareCloudProfile(pkg, cloudProfileName, path, dexMetadataPath)) {
+ profileName = cloudProfileName;
+ } else {
+ // Fall back to use the shared filter.
+ compilerFilter =
+ PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+ PackageManagerService.REASON_SHARED);
+ profileName = null;
}
+
+ // We still run `analyseProfiles` even if `useCloudProfile` is true because it
+ // merges profiles into the reference profile, which a system API
+ // `ArtManager.snapshotRuntimeProfile` takes snapshots from. However, we don't
+ // want the result to affect the decision of whether dexopt is needed.
+ profileAnalysisResult = PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
}
- // Should stop the operation immediately.
- if (newResult == DEX_OPT_CANCELLED) {
- // Even for the cancellation, return failed if has failed.
- if (result == DEX_OPT_FAILED) {
- return result;
+ // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct
+ // flags.
+ final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter,
+ useCloudProfile, options);
+
+ for (String dexCodeIsa : dexCodeInstructionSets) {
+ int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter,
+ profileAnalysisResult, classLoaderContexts[i], dexoptFlags, sharedGid,
+ packageStats, options.isDowngrade(), profileName, dexMetadataPath,
+ options.getCompilationReason());
+ // OTAPreopt doesn't have stats so don't report in that case.
+ if (packageStats != null) {
+ Trace.traceBegin(Trace.TRACE_TAG_PACKAGE_MANAGER, "dex2oat-metrics");
+ try {
+ long sessionId = sRandom.nextLong();
+ ArtStatsLogUtils.writeStatsLog(
+ mArtStatsLogger,
+ sessionId,
+ compilerFilter,
+ pkg.getUid(),
+ packageStats.getCompileTime(path),
+ dexMetadataPath,
+ options.getCompilationReason(),
+ newResult,
+ ArtStatsLogUtils.getApkType(path, pkg.getBaseApkPath(),
+ pkg.getSplitCodePaths()),
+ dexCodeIsa,
+ path);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ // Should stop the operation immediately.
+ if (newResult == DEX_OPT_CANCELLED) {
+ // Even for the cancellation, return failed if has failed.
+ if (result == DEX_OPT_FAILED) {
+ return result;
+ }
+ return newResult;
+ }
+ // The end result is:
+ // - FAILED if any path failed,
+ // - PERFORMED if at least one path needed compilation,
+ // - SKIPPED when all paths are up to date
+ if ((result != DEX_OPT_FAILED) && (newResult != DEX_OPT_SKIPPED)) {
+ result = newResult;
}
- return newResult;
}
- // The end result is:
- // - FAILED if any path failed,
- // - PERFORMED if at least one path needed compilation,
- // - SKIPPED when all paths are up to date
- if ((result != DEX_OPT_FAILED) && (newResult != DEX_OPT_SKIPPED)) {
- result = newResult;
+ } finally {
+ if (cloudProfileName != null) {
+ try {
+ mInstaller.deleteReferenceProfile(pkg.getPackageName(), cloudProfileName);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to cleanup cloud profile", e);
+ }
}
}
}
@@ -405,22 +427,25 @@ public class PackageDexOptimizer {
}
/**
- * Resets the profiles of the dex file at {@code path} belonging to the package {@code pkg} to
- * the initial state as if the package is newly installed. Returns true on success, or false
- * otherwise.
+ * Creates a profile with the name {@code profileName} from the dex metadata file at {@code
+ * dexMetadataPath} for the dex file at {@code path} belonging to the package {@code pkg}.
+ *
+ * @return true on success, or false otherwise.
*/
@GuardedBy("mInstallLock")
- private boolean resetProfile(AndroidPackage pkg, String profileName, String path,
+ private boolean prepareCloudProfile(AndroidPackage pkg, String profileName, String path,
@Nullable String dexMetadataPath) {
if (dexMetadataPath != null) {
try {
- mInstaller.clearAppProfiles(pkg.getPackageName(), profileName);
+ // Make sure we don't keep any existing contents.
+ mInstaller.deleteReferenceProfile(pkg.getPackageName(), profileName);
+
final int appId = UserHandle.getAppId(pkg.getUid());
- mInstaller.prepareAppProfile(pkg.getPackageName(), UserHandle.USER_NULL,
- appId, profileName, path, dexMetadataPath);
+ mInstaller.prepareAppProfile(pkg.getPackageName(), UserHandle.USER_NULL, appId,
+ profileName, path, dexMetadataPath);
return true;
} catch (InstallerException e) {
- Slog.w(TAG, "Failed to reset profile", e);
+ Slog.w(TAG, "Failed to prepare cloud profile", e);
return false;
}
} else {
@@ -835,16 +860,16 @@ public class PackageDexOptimizer {
private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
return getDexFlags((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0,
info.getHiddenApiEnforcementPolicy(), info.splitDependencies,
- info.requestsIsolatedSplitLoading(), compilerFilter, false /* resetProfile */,
+ info.requestsIsolatedSplitLoading(), compilerFilter, false /* useCloudProfile */,
options);
}
private int getDexFlags(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting,
- String compilerFilter, boolean resetProfile, DexoptOptions options) {
+ String compilerFilter, boolean useCloudProfile, DexoptOptions options) {
return getDexFlags(pkg.isDebuggable(),
AndroidPackageUtils.getHiddenApiEnforcementPolicy(pkg, pkgSetting),
pkg.getSplitDependencies(), pkg.isIsolatedSplitLoading(), compilerFilter,
- resetProfile, options);
+ useCloudProfile, options);
}
/**
@@ -853,15 +878,15 @@ public class PackageDexOptimizer {
*/
private int getDexFlags(boolean debuggable, int hiddenApiEnforcementPolicy,
SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading,
- String compilerFilter, boolean resetProfile, DexoptOptions options) {
+ String compilerFilter, boolean useCloudProfile, DexoptOptions options) {
// Profile guide compiled oat files should not be public unles they are based
// on profiles from dex metadata archives.
// The flag isDexoptInstallWithDexMetadata applies only on installs when we know that
// the user does not have an existing profile.
- // The flag resetProfile applies only when the existing profile is already reset.
+ // The flag useCloudProfile applies only when the cloud profile should be used.
boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata()
- || resetProfile;
+ || useCloudProfile;
int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
// Some apps are executed with restrictions on hidden API usage. If this app is one
// of them, pass a flag to dexopt to enable the same restrictions during compilation.
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 1efaa735a56c..7c900ef9401a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1741,7 +1741,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static boolean isSecureFrpInstallAllowed(Context context, int callingUid) {
final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
final String[] systemInstaller = pmi.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM);
+ KnownPackages.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM);
final AndroidPackage callingInstaller = pmi.getPackage(callingUid);
if (callingInstaller != null
&& ArrayUtils.contains(systemInstaller, callingInstaller.getPackageName())) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index 2b733754685e..2fe7913342a2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -83,6 +83,7 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
@NonNull protected abstract PackageObserverHelper getPackageObserverHelper();
@NonNull protected abstract ResolveIntentHelper getResolveIntentHelper();
@NonNull protected abstract SuspendPackageHelper getSuspendPackageHelper();
+ @NonNull protected abstract DistractingPackageHelper getDistractingPackageHelper();
@NonNull protected abstract ProtectedPackages getProtectedPackages();
@NonNull protected abstract UserNeedsBadgingCache getUserNeedsBadging();
@NonNull protected abstract InstantAppRegistry getInstantAppRegistry();
@@ -248,8 +249,8 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
@Override
@Deprecated
public final void removeDistractingPackageRestrictions(String packageName, int userId) {
- mService.removeDistractingPackageRestrictions(snapshot(), new String[]{packageName},
- userId);
+ getDistractingPackageHelper().removeDistractingPackageRestrictions(snapshot(),
+ new String[]{packageName}, userId);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4c7243decb07..4f152d6c0819 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -159,7 +159,6 @@ import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.ExceptionUtils;
-import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -655,9 +654,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService
final ProtectedPackages mProtectedPackages;
- @GuardedBy("mLoadedVolumes")
- final ArraySet<String> mLoadedVolumes = new ArraySet<>();
-
private boolean mFirstBoot;
final boolean mIsEngBuild;
@@ -667,7 +663,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy;
@GuardedBy("mAvailableFeatures")
- final ArrayMap<String, FeatureInfo> mAvailableFeatures;
+ private final ArrayMap<String, FeatureInfo> mAvailableFeatures;
@Watched
final InstantAppRegistry mInstantAppRegistry;
@@ -724,7 +720,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
@Watched
- final AppsFilter mAppsFilter;
+ final AppsFilterImpl mAppsFilter;
final PackageParser2.Callback mPackageParserCallback;
@@ -942,7 +938,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService
private final ResolveIntentHelper mResolveIntentHelper;
private final DexOptHelper mDexOptHelper;
private final SuspendPackageHelper mSuspendPackageHelper;
+ private final DistractingPackageHelper mDistractingPackageHelper;
private final IntentResolverInterceptor mIntentResolverInterceptor;
+ private final StorageEventHelper mStorageEventHelper;
/**
* Invalidate the package info cache, which includes updating the cached computer.
@@ -981,7 +979,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
public final InstantAppRegistry instantAppRegistry;
public final ApplicationInfo androidApplication;
public final String appPredictionServicePackage;
- public final AppsFilter appsFilter;
+ public final AppsFilterSnapshot appsFilter;
public final ComponentResolverApi componentResolver;
public final PackageManagerService service;
public final WatchedArrayMap<String, Integer> frozenPackages;
@@ -1433,7 +1431,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
RuntimePermissionsPersistence.createInstance(),
i.getPermissionManagerServiceInternal(),
domainVerificationService, lock),
- (i, pm) -> AppsFilter.create(i, i.getLocalService(PackageManagerInternal.class)),
+ (i, pm) -> AppsFilterImpl.create(i,
+ i.getLocalService(PackageManagerInternal.class)),
(i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"),
(i, pm) -> SystemConfig.getInstance(),
(i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(),
@@ -1584,7 +1583,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
/**
- * A extremely minimal constructor designed to start up a PackageManagerService instance for
+ * An extremely minimal constructor designed to start up a PackageManagerService instance for
* testing.
*
* It is assumed that all methods under test will mock the internal fields and thus
@@ -1685,10 +1684,12 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mResolveIntentHelper = testParams.resolveIntentHelper;
mDexOptHelper = testParams.dexOptHelper;
mSuspendPackageHelper = testParams.suspendPackageHelper;
+ mDistractingPackageHelper = testParams.distractingPackageHelper;
mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
mIntentResolverInterceptor = null;
+ mStorageEventHelper = testParams.storageEventHelper;
registerObservers(false);
invalidatePackageInfoCache();
@@ -1841,6 +1842,10 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mDexOptHelper = new DexOptHelper(this);
mSuspendPackageHelper = new SuspendPackageHelper(this, mInjector, mBroadcastHelper,
mProtectedPackages);
+ mStorageEventHelper = new StorageEventHelper(this, mDeletePackageHelper,
+ mRemovePackageHelper);
+ mDistractingPackageHelper = new DistractingPackageHelper(this, mInjector, mBroadcastHelper,
+ mSuspendPackageHelper);
synchronized (mLock) {
// Create the computer as soon as the state objects have been installed. The
@@ -3064,43 +3069,19 @@ public class PackageManagerService implements PackageSender, TestUtilityService
void removeAllDistractingPackageRestrictions(@NonNull Computer snapshot, int userId) {
final String[] allPackages = snapshot.getAllAvailablePackageNames();
- removeDistractingPackageRestrictions(snapshot, allPackages, userId);
+ mDistractingPackageHelper.removeDistractingPackageRestrictions(snapshot, allPackages,
+ userId);
}
- /**
- * Removes any {@link android.content.pm.PackageManager.DistractionRestriction restrictions}
- * set on given packages.
- *
- * <p> Caller must flush package restrictions if it cares about immediate data consistency.
- *
- * @param packagesToChange The packages on which restrictions are to be removed.
- * @param userId the user for which changes are taking place.
- */
- void removeDistractingPackageRestrictions(@NonNull Computer snapshot,
- String[] packagesToChange, int userId) {
- final List<String> changedPackages = new ArrayList<>();
- final IntArray changedUids = new IntArray();
- for (String packageName : packagesToChange) {
- final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName);
- if (ps != null && ps.getUserStateOrDefault(userId).getDistractionFlags() != 0) {
- changedPackages.add(ps.getPackageName());
- changedUids.add(UserHandle.getUid(userId, ps.getAppId()));
- }
- }
- commitPackageStateMutation(null, mutator -> {
- for (int index = 0; index < changedPackages.size(); index++) {
- mutator.forPackage(changedPackages.get(index))
- .userState(userId)
- .setDistractionFlags(0);
- }
- });
+ private void enforceCanSetDistractingPackageRestrictionsAsUser(@NonNull Computer snapshot,
+ int callingUid, int userId, String callingMethod) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
+ callingMethod);
- if (!changedPackages.isEmpty()) {
- final String[] packageArray = changedPackages.toArray(
- new String[changedPackages.size()]);
- mHandler.post(() -> mBroadcastHelper.sendDistractingPackagesChanged(
- packageArray, changedUids.toArray(), userId, 0));
- scheduleWritePackageRestrictions(userId);
+ if (callingUid != Process.ROOT_UID && callingUid != Process.SYSTEM_UID
+ && UserHandle.getUserId(callingUid) != userId) {
+ throw new SecurityException("Calling uid " + callingUid + " cannot call for user "
+ + userId);
}
}
@@ -4055,17 +4036,15 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mUserManager.systemReady();
// Watch for external volumes that come and go over time
- final StorageEventHelper storageEventHelper = new StorageEventHelper(this,
- mDeletePackageHelper, mRemovePackageHelper);
final StorageManager storage = mInjector.getSystemService(StorageManager.class);
- storage.registerListener(storageEventHelper);
+ storage.registerListener(mStorageEventHelper);
mInstallerService.systemReady();
mPackageDexOptimizer.systemReady();
// Now that we're mostly running, clean up stale users and apps
mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
- storageEventHelper.reconcileApps(snapshotComputer(), StorageManager.UUID_PRIVATE_INTERNAL);
+ mStorageEventHelper.reconcileApps(snapshotComputer(), StorageManager.UUID_PRIVATE_INTERNAL);
mPermissionManager.onSystemReady();
@@ -4163,20 +4142,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
}
- void dumpSnapshotStats(PrintWriter pw, boolean isBrief) {
- if (mSnapshotStatistics == null) {
- return;
- }
- int hits = 0;
- synchronized (mSnapshotLock) {
- if (mSnapshotComputer != null) {
- hits = mSnapshotComputer.getUsed();
- }
- }
- final long now = SystemClock.currentTimeMicro();
- mSnapshotStatistics.dump(pw, " ", now, hits, -1, isBrief);
- }
-
//TODO: b/111402650
private void disableSkuSpecificApps() {
String[] apkList = mContext.getResources().getStringArray(
@@ -4221,17 +4186,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
}
- /**
- * Verify that given package is currently frozen.
- */
- void checkPackageFrozen(String packageName) {
- synchronized (mLock) {
- if (!mFrozenPackages.containsKey(packageName)) {
- Slog.wtf(TAG, "Expected " + packageName + " to be frozen!", new Throwable());
- }
- }
- }
-
/** Called by UserManagerService */
void cleanUpUser(UserManagerService userManager, @UserIdInt int userId) {
synchronized (mLock) {
@@ -5617,73 +5571,13 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
public String[] setDistractingPackageRestrictionsAsUser(String[] packageNames,
int restrictionFlags, int userId) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
- "setDistractingPackageRestrictionsAsUser");
-
final int callingUid = Binder.getCallingUid();
- if (callingUid != Process.ROOT_UID && callingUid != Process.SYSTEM_UID
- && UserHandle.getUserId(callingUid) != userId) {
- throw new SecurityException("Calling uid " + callingUid + " cannot call for user "
- + userId);
- }
- Objects.requireNonNull(packageNames, "packageNames cannot be null");
final Computer snapshot = snapshotComputer();
- if (restrictionFlags != 0
- && !mSuspendPackageHelper.isSuspendAllowedForUser(snapshot, userId,
- callingUid)) {
- Slog.w(PackageManagerService.TAG, "Cannot restrict packages due to restrictions on user " + userId);
- return packageNames;
- }
-
- final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
- final IntArray changedUids = new IntArray(packageNames.length);
- final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
-
- ArraySet<String> changesToCommit = new ArraySet<>();
- final boolean[] canRestrict = (restrictionFlags != 0)
- ? mSuspendPackageHelper.canSuspendPackageForUser(snapshot, packageNames, userId,
- callingUid) : null;
- for (int i = 0; i < packageNames.length; i++) {
- final String packageName = packageNames[i];
- final PackageStateInternal packageState =
- snapshot.getPackageStateInternal(packageName);
- if (packageState == null
- || snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
- Slog.w(PackageManagerService.TAG, "Could not find package setting for package: " + packageName
- + ". Skipping...");
- unactionedPackages.add(packageName);
- continue;
- }
- if (canRestrict != null && !canRestrict[i]) {
- unactionedPackages.add(packageName);
- continue;
- }
- final int oldDistractionFlags = packageState.getUserStateOrDefault(userId)
- .getDistractionFlags();
- if (restrictionFlags != oldDistractionFlags) {
- changedPackagesList.add(packageName);
- changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
- changesToCommit.add(packageName);
- }
- }
-
- commitPackageStateMutation(null, mutator -> {
- final int size = changesToCommit.size();
- for (int index = 0; index < size; index++) {
- mutator.forPackage(changesToCommit.valueAt(index))
- .userState(userId)
- .setDistractionFlags(restrictionFlags);
- }
- });
-
- if (!changedPackagesList.isEmpty()) {
- final String[] changedPackages = changedPackagesList.toArray(
- new String[changedPackagesList.size()]);
- mHandler.post(() -> mBroadcastHelper.sendDistractingPackagesChanged(
- changedPackages, changedUids.toArray(), userId, restrictionFlags));
- scheduleWritePackageRestrictions(userId);
- }
- return unactionedPackages.toArray(new String[0]);
+ enforceCanSetDistractingPackageRestrictionsAsUser(snapshot, callingUid, userId,
+ "setDistractingPackageRestrictionsAsUser");
+ Objects.requireNonNull(packageNames, "packageNames cannot be null");
+ return mDistractingPackageHelper.setDistractingPackageRestrictionsAsUser(snapshot,
+ packageNames, restrictionFlags, userId, callingUid);
}
@Override
@@ -6050,7 +5944,37 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
- new DumpHelper(PackageManagerService.this).doDump(fd, pw, args);
+ final Computer snapshot = snapshotComputer();
+ final KnownPackages knownPackages = new KnownPackages(
+ mDefaultAppProvider,
+ mRequiredInstallerPackage,
+ mRequiredUninstallerPackage,
+ mSetupWizardPackage,
+ mRequiredVerifierPackage,
+ mDefaultTextClassifierPackage,
+ mSystemTextClassifierPackageName,
+ mRequiredPermissionControllerPackage,
+ mConfiguratorPackage,
+ mIncidentReportApproverPackage,
+ mAmbientContextDetectionPackage,
+ mAppPredictionServicePackage,
+ COMPANION_PACKAGE_NAME,
+ mRetailDemoPackage,
+ mOverlayConfigSignaturePackage,
+ mRecentsPackage);
+ final ArrayMap<String, FeatureInfo> availableFeatures;
+ synchronized (mAvailableFeatures) {
+ availableFeatures = new ArrayMap<>(mAvailableFeatures);
+ }
+ final ArraySet<String> protectedBroadcasts;
+ synchronized (mProtectedBroadcasts) {
+ protectedBroadcasts = new ArraySet<>(mProtectedBroadcasts);
+ }
+ new DumpHelper(mPermissionManager, mApexManager, mStorageEventHelper,
+ mDomainVerificationManager, mInstallerService, mRequiredVerifierPackage,
+ knownPackages, mChangedPackagesTracker, availableFeatures, protectedBroadcasts,
+ getPerUidReadTimeouts(snapshot)
+ ).doDump(snapshot, fd, pw, args);
}
}
@@ -6117,6 +6041,12 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@NonNull
@Override
+ protected DistractingPackageHelper getDistractingPackageHelper() {
+ return mDistractingPackageHelper;
+ }
+
+ @NonNull
+ @Override
protected ProtectedPackages getProtectedPackages() {
return mProtectedPackages;
}
@@ -6984,45 +6914,24 @@ public class PackageManagerService implements PackageSender, TestUtilityService
String[] getKnownPackageNamesInternal(@NonNull Computer snapshot, int knownPackage,
int userId) {
- switch (knownPackage) {
- case PackageManagerInternal.PACKAGE_BROWSER:
- return new String[] { mDefaultAppProvider.getDefaultBrowser(userId) };
- case PackageManagerInternal.PACKAGE_INSTALLER:
- return snapshot.filterOnlySystemPackages(mRequiredInstallerPackage);
- case PackageManagerInternal.PACKAGE_UNINSTALLER:
- return snapshot.filterOnlySystemPackages(mRequiredUninstallerPackage);
- case PackageManagerInternal.PACKAGE_SETUP_WIZARD:
- return snapshot.filterOnlySystemPackages(mSetupWizardPackage);
- case PackageManagerInternal.PACKAGE_SYSTEM:
- return new String[]{"android"};
- case PackageManagerInternal.PACKAGE_VERIFIER:
- return snapshot.filterOnlySystemPackages(mRequiredVerifierPackage);
- case PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER:
- return snapshot.filterOnlySystemPackages(
- mDefaultTextClassifierPackage, mSystemTextClassifierPackageName);
- case PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER:
- return snapshot.filterOnlySystemPackages(mRequiredPermissionControllerPackage);
- case PackageManagerInternal.PACKAGE_CONFIGURATOR:
- return snapshot.filterOnlySystemPackages(mConfiguratorPackage);
- case PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER:
- return snapshot.filterOnlySystemPackages(mIncidentReportApproverPackage);
- case PackageManagerInternal.PACKAGE_AMBIENT_CONTEXT_DETECTION:
- return snapshot.filterOnlySystemPackages(mAmbientContextDetectionPackage);
- case PackageManagerInternal.PACKAGE_APP_PREDICTOR:
- return snapshot.filterOnlySystemPackages(mAppPredictionServicePackage);
- case PackageManagerInternal.PACKAGE_COMPANION:
- return snapshot.filterOnlySystemPackages(COMPANION_PACKAGE_NAME);
- case PackageManagerInternal.PACKAGE_RETAIL_DEMO:
- return TextUtils.isEmpty(mRetailDemoPackage)
- ? ArrayUtils.emptyArray(String.class)
- : new String[] {mRetailDemoPackage};
- case PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE:
- return snapshot.filterOnlySystemPackages(mOverlayConfigSignaturePackage);
- case PackageManagerInternal.PACKAGE_RECENTS:
- return snapshot.filterOnlySystemPackages(mRecentsPackage);
- default:
- return ArrayUtils.emptyArray(String.class);
- }
+ return new KnownPackages(
+ mDefaultAppProvider,
+ mRequiredInstallerPackage,
+ mRequiredUninstallerPackage,
+ mSetupWizardPackage,
+ mRequiredVerifierPackage,
+ mDefaultTextClassifierPackage,
+ mSystemTextClassifierPackageName,
+ mRequiredPermissionControllerPackage,
+ mConfiguratorPackage,
+ mIncidentReportApproverPackage,
+ mAmbientContextDetectionPackage,
+ mAppPredictionServicePackage,
+ COMPANION_PACKAGE_NAME,
+ mRetailDemoPackage,
+ mOverlayConfigSignaturePackage,
+ mRecentsPackage)
+ .getKnownPackageNames(snapshot, knownPackage, userId);
}
String getActiveLauncherPackageName(int userId) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
index a02237fa90ce..396994b04514 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
@@ -99,7 +99,7 @@ public class PackageManagerServiceInjector {
private final Singleton<UserManagerService>
mUserManagerProducer;
private final Singleton<Settings> mSettingsProducer;
- private final Singleton<AppsFilter> mAppsFilterProducer;
+ private final Singleton<AppsFilterImpl> mAppsFilterProducer;
private final Singleton<PlatformCompat>
mPlatformCompatProducer;
private final Singleton<SystemConfig> mSystemConfigProducer;
@@ -148,7 +148,7 @@ public class PackageManagerServiceInjector {
Producer<PermissionManagerServiceInternal> permissionManagerServiceProducer,
Producer<UserManagerService> userManagerProducer,
Producer<Settings> settingsProducer,
- Producer<AppsFilter> appsFilterProducer,
+ Producer<AppsFilterImpl> appsFilterProducer,
Producer<PlatformCompat> platformCompatProducer,
Producer<SystemConfig> systemConfigProducer,
Producer<PackageDexOptimizer> packageDexOptimizerProducer,
@@ -282,7 +282,7 @@ public class PackageManagerServiceInjector {
return mSettingsProducer.get(this, mPackageManager);
}
- public AppsFilter getAppsFilter() {
+ public AppsFilterImpl getAppsFilter() {
return mAppsFilterProducer.get(this, mPackageManager);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index e466fe2c0e31..16829e0e8f6c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -115,4 +115,6 @@ public final class PackageManagerServiceTestParams {
public ResolveIntentHelper resolveIntentHelper;
public DexOptHelper dexOptHelper;
public SuspendPackageHelper suspendPackageHelper;
+ public StorageEventHelper storageEventHelper;
+ public DistractingPackageHelper distractingPackageHelper;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 581e4e26da81..e142ed631092 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -128,6 +128,7 @@ import java.util.Base64;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -829,7 +830,7 @@ class PackageManagerShellCommand extends ShellCommand {
boolean showVersionCode = false;
boolean listApexOnly = false;
int uid = -1;
- int userId = UserHandle.USER_SYSTEM;
+ int defaultUserId = UserHandle.USER_ALL;
try {
String opt;
while ((opt = getNextOption()) != null) {
@@ -873,7 +874,7 @@ class PackageManagerShellCommand extends ShellCommand {
listApexOnly = true;
break;
case "--user":
- userId = UserHandle.parseUserArg(getNextArgRequired());
+ defaultUserId = UserHandle.parseUserArg(getNextArgRequired());
break;
case "--uid":
showUid = true;
@@ -891,84 +892,104 @@ class PackageManagerShellCommand extends ShellCommand {
final String filter = getNextArg();
- if (userId == UserHandle.USER_ALL) {
- getFlags |= PackageManager.MATCH_KNOWN_PACKAGES;
+ int[] userIds = {defaultUserId};
+ if (defaultUserId == UserHandle.USER_ALL) {
+ final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
+ userIds = umi.getUserIds();
}
if (showSdks) {
getFlags |= PackageManager.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES;
}
- final int translatedUserId =
- translateUserId(userId, UserHandle.USER_SYSTEM, "runListPackages");
- @SuppressWarnings("unchecked")
- final ParceledListSlice<PackageInfo> slice =
- mInterface.getInstalledPackages(getFlags, translatedUserId);
- final List<PackageInfo> packages = slice.getList();
-
- final int count = packages.size();
- for (int p = 0; p < count; p++) {
- final PackageInfo info = packages.get(p);
- if (filter != null && !info.packageName.contains(filter)) {
- continue;
- }
- final boolean isApex = info.isApex;
- if (uid != -1 && !isApex && info.applicationInfo.uid != uid) {
- continue;
- }
- final boolean isSystem = !isApex &&
- (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
- final boolean isEnabled = !isApex && info.applicationInfo.enabled;
- if ((listDisabled && isEnabled) ||
- (listEnabled && !isEnabled) ||
- (listSystem && !isSystem) ||
- (listThirdParty && isSystem) ||
- (listApexOnly && !isApex)) {
- continue;
- }
-
- String name = null;
- if (showSdks) {
- final ParceledListSlice<SharedLibraryInfo> libsSlice =
- mInterface.getDeclaredSharedLibraries(info.packageName, getFlags, userId);
- if (libsSlice == null) {
+ // Build a map of packages to a list of corresponding uids. Keys are strings containing
+ // the sdk or package name along with optional additional information based on opt.
+ final Map<String, List<String>> out = new HashMap<>();
+ for (int userId : userIds) {
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_SYSTEM, "runListPackages");
+ @SuppressWarnings("unchecked") final ParceledListSlice<PackageInfo> slice =
+ mInterface.getInstalledPackages(getFlags, translatedUserId);
+ final List<PackageInfo> packages = slice.getList();
+
+ final int count = packages.size();
+ for (int p = 0; p < count; p++) {
+ final PackageInfo info = packages.get(p);
+ final StringBuilder stringBuilder = new StringBuilder();
+ if (filter != null && !info.packageName.contains(filter)) {
continue;
}
- final List<SharedLibraryInfo> libs = libsSlice.getList();
- for (int l = 0, lsize = libs.size(); l < lsize; ++l) {
- SharedLibraryInfo lib = libs.get(l);
- if (lib.getType() == SharedLibraryInfo.TYPE_SDK_PACKAGE) {
- name = lib.getName() + ":" + lib.getLongVersion();
- break;
- }
+ final boolean isApex = info.isApex;
+ if (uid != -1 && !isApex && info.applicationInfo.uid != uid) {
+ continue;
}
- if (name == null) {
+
+ final boolean isSystem = !isApex
+ && (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ final boolean isEnabled = !isApex && info.applicationInfo.enabled;
+ if ((listDisabled && isEnabled)
+ || (listEnabled && !isEnabled)
+ || (listSystem && !isSystem)
+ || (listThirdParty && isSystem)
+ || (listApexOnly && !isApex)) {
continue;
}
- } else {
- name = info.packageName;
- }
- pw.print(prefix);
- if (showSourceDir) {
- pw.print(info.applicationInfo.sourceDir);
- pw.print("=");
- }
- pw.print(name);
- if (showVersionCode) {
- pw.print(" versionCode:");
- if (info.applicationInfo != null) {
- pw.print(info.applicationInfo.longVersionCode);
+ String name = null;
+ if (showSdks) {
+ final ParceledListSlice<SharedLibraryInfo> libsSlice =
+ mInterface.getDeclaredSharedLibraries(
+ info.packageName, getFlags, userId
+ );
+ if (libsSlice == null) {
+ continue;
+ }
+ final List<SharedLibraryInfo> libs = libsSlice.getList();
+ for (int l = 0, lsize = libs.size(); l < lsize; ++l) {
+ SharedLibraryInfo lib = libs.get(l);
+ if (lib.getType() == SharedLibraryInfo.TYPE_SDK_PACKAGE) {
+ name = lib.getName() + ":" + lib.getLongVersion();
+ break;
+ }
+ }
+ if (name == null) {
+ continue;
+ }
} else {
- pw.print(info.getLongVersionCode());
+ name = info.packageName;
+ }
+
+ stringBuilder.append(prefix);
+ if (showSourceDir) {
+ stringBuilder.append(info.applicationInfo.sourceDir);
+ stringBuilder.append("=");
+ }
+ stringBuilder.append(name);
+ if (showVersionCode) {
+ stringBuilder.append(" versionCode:");
+ if (info.applicationInfo != null) {
+ stringBuilder.append(info.applicationInfo.longVersionCode);
+ } else {
+ stringBuilder.append(info.getLongVersionCode());
+ }
+ }
+ if (listInstaller) {
+ stringBuilder.append(" installer=");
+ stringBuilder.append(mInterface.getInstallerPackageName(info.packageName));
+ }
+ List<String> uids = out.computeIfAbsent(
+ stringBuilder.toString(), k -> new ArrayList<>()
+ );
+ if (showUid && !isApex) {
+ uids.add(String.valueOf(info.applicationInfo.uid));
}
}
- if (listInstaller) {
- pw.print(" installer=");
- pw.print(mInterface.getInstallerPackageName(info.packageName));
- }
- if (showUid && !isApex) {
+ }
+ for (Map.Entry<String, List<String>> entry : out.entrySet()) {
+ pw.print(entry.getKey());
+ List<String> uids = entry.getValue();
+ if (!uids.isEmpty()) {
pw.print(" uid:");
- pw.print(info.applicationInfo.uid);
+ pw.print(String.join(",", uids));
}
pw.println();
}
@@ -2675,7 +2696,8 @@ class PackageManagerShellCommand extends ShellCommand {
while ((opt = getNextOption()) != null) {
String newUserType = null;
if ("--profileOf".equals(opt)) {
- userId = UserHandle.parseUserArg(getNextArgRequired());
+ userId = translateUserId(UserHandle.parseUserArg(getNextArgRequired()),
+ UserHandle.USER_ALL, "runCreateUser");
} else if ("--managed".equals(opt)) {
newUserType = UserManager.USER_TYPE_PROFILE_MANAGED;
} else if ("--restricted".equals(opt)) {
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index b181cdd92379..baa3a9d85b0a 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -17,6 +17,7 @@
package com.android.server.pm;
import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.incremental.IncrementalManager.isIncrementalPath;
import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
@@ -29,6 +30,7 @@ import static com.android.server.pm.PackageManagerService.TAG;
import android.annotation.NonNull;
import android.content.pm.PackageManager;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.incremental.IncrementalManager;
import android.util.Log;
@@ -334,10 +336,19 @@ final class RemovePackageHelper {
mPm.mSettings.writeKernelMappingLPr(deletedPs);
}
}
+
if (removedAppId != -1) {
- // A user ID was deleted here. Go through all users and remove it
- // from KeyStore.
- mAppDataHelper.clearKeystoreData(UserHandle.USER_ALL, removedAppId);
+ // A user ID was deleted here. Go through all users and remove it from KeyStore.
+ final int appIdToRemove = removedAppId;
+ mPm.mInjector.getBackgroundHandler().post(() -> {
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,
+ "clearKeystoreData:" + appIdToRemove);
+ mAppDataHelper.clearKeystoreData(UserHandle.USER_ALL, appIdToRemove);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ });
}
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 9ce4cdf840fd..b3723fb61f5a 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -1169,7 +1169,7 @@ class ShortcutPackage extends ShortcutPackageItem {
// This will send a notification to the launcher, and also save .
// TODO: List changed and removed manifest shortcuts and pass to packageShortcutsChanged()
- s.packageShortcutsChanged(getPackageName(), getPackageUserId(), null, null);
+ s.packageShortcutsChanged(this, null, null);
return true;
}
@@ -1446,7 +1446,7 @@ class ShortcutPackage extends ShortcutPackageItem {
});
}
if (!CollectionUtils.isEmpty(changedShortcuts)) {
- s.packageShortcutsChanged(getPackageName(), getPackageUserId(), changedShortcuts, null);
+ s.packageShortcutsChanged(this, changedShortcuts, null);
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
index c1f57f970127..1e1f17894605 100644
--- a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
+++ b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
@@ -454,6 +454,7 @@ class ShortcutRequestPinProcessor {
final String shortcutId = original.getId();
List<ShortcutInfo> changedShortcuts = null;
+ final ShortcutPackage ps;
synchronized (mLock) {
if (!(mService.isUserUnlockedL(appUserId)
@@ -472,8 +473,7 @@ class ShortcutRequestPinProcessor {
return true;
}
- final ShortcutPackage ps = mService.getPackageShortcutsForPublisherLocked(
- appPackageName, appUserId);
+ ps = mService.getPackageShortcutsForPublisherLocked(appPackageName, appUserId);
final ShortcutInfo current = ps.findShortcutById(shortcutId);
// The shortcut might have been changed, so we need to do the same validation again.
@@ -527,7 +527,7 @@ class ShortcutRequestPinProcessor {
}
mService.verifyStates();
- mService.packageShortcutsChanged(appPackageName, appUserId, changedShortcuts, null);
+ mService.packageShortcutsChanged(ps, changedShortcuts, null);
return true;
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 9ca4f247891d..056f25542294 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -221,6 +221,8 @@ public class ShortcutService extends IShortcutService.Stub {
private static final String DUMMY_MAIN_ACTIVITY = "android.__dummy__";
+ private static final long CALLBACK_DELAY = 100L;
+
@VisibleForTesting
interface ConfigConstants {
/**
@@ -593,6 +595,9 @@ public class ShortcutService extends IShortcutService.Stub {
@Override public void onUidCachedChanged(int uid, boolean cached) {
}
+
+ @Override public void onUidProcAdjChanged(int uid) {
+ }
};
void handleOnUidStateChanged(int uid, int procState) {
@@ -1745,9 +1750,13 @@ public class ShortcutService extends IShortcutService.Stub {
new Thread(r).start();
}
- void injectPostToHandlerIfAppSearch(Runnable r) {
- // TODO: move to background thread when app search is enabled.
- r.run();
+ void injectPostToHandlerDebounced(@NonNull final Object token, @NonNull final Runnable r) {
+ Objects.requireNonNull(token);
+ Objects.requireNonNull(r);
+ synchronized (mLock) {
+ mHandler.removeCallbacksAndMessages(token);
+ mHandler.postDelayed(r, token, CALLBACK_DELAY);
+ }
}
/**
@@ -1771,20 +1780,33 @@ public class ShortcutService extends IShortcutService.Stub {
* - Sends a notification to LauncherApps
* - Write to file
*/
- void packageShortcutsChanged(@NonNull String packageName, @UserIdInt int userId,
+ void packageShortcutsChanged(
+ @NonNull final ShortcutPackage sp,
@Nullable final List<ShortcutInfo> changedShortcuts,
@Nullable final List<ShortcutInfo> removedShortcuts) {
- notifyListeners(packageName, userId);
+ Objects.requireNonNull(sp);
+ final String packageName = sp.getPackageName();
+ final int userId = sp.getPackageUserId();
+ if (DEBUG) {
+ Slog.d(TAG, String.format(
+ "Shortcut changes: package=%s, user=%d", packageName, userId));
+ }
+ injectPostToHandlerDebounced(sp, notifyListenerRunnable(packageName, userId));
notifyShortcutChangeCallbacks(packageName, userId, changedShortcuts, removedShortcuts);
scheduleSaveUser(userId);
}
- private void notifyListeners(@NonNull String packageName, @UserIdInt int userId) {
+ private void notifyListeners(@NonNull final String packageName, @UserIdInt final int userId) {
if (DEBUG) {
Slog.d(TAG, String.format(
"Shortcut changes: package=%s, user=%d", packageName, userId));
}
- injectPostToHandler(() -> {
+ injectPostToHandler(notifyListenerRunnable(packageName, userId));
+ }
+
+ private Runnable notifyListenerRunnable(@NonNull final String packageName,
+ @UserIdInt final int userId) {
+ return () -> {
try {
final ArrayList<ShortcutChangeListener> copy;
synchronized (mLock) {
@@ -1800,7 +1822,7 @@ public class ShortcutService extends IShortcutService.Stub {
}
} catch (Exception ignore) {
}
- });
+ };
}
private void notifyShortcutChangeCallbacks(@NonNull String packageName, @UserIdInt int userId,
@@ -1948,12 +1970,12 @@ public class ShortcutService extends IShortcutService.Stub {
List<ShortcutInfo> changedShortcuts = null;
List<ShortcutInfo> removedShortcuts = null;
+ final ShortcutPackage ps;
synchronized (mLock) {
throwIfUserLockedL(userId);
- final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName,
- userId);
+ ps = getPackageShortcutsForPublisherLocked(packageName, userId);
ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true);
ps.ensureNoBitmapIconIfShortcutIsLongLived(newShortcuts);
@@ -1997,7 +2019,7 @@ public class ShortcutService extends IShortcutService.Stub {
cachedOrPinned, newShortcuts, removedShortcuts, ps);
}
- packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
+ packageShortcutsChanged(ps, changedShortcuts, removedShortcuts);
verifyStates();
@@ -2017,12 +2039,12 @@ public class ShortcutService extends IShortcutService.Stub {
final int size = newShortcuts.size();
final List<ShortcutInfo> changedShortcuts = new ArrayList<>(1);
+ final ShortcutPackage ps;
synchronized (mLock) {
throwIfUserLockedL(userId);
- final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName,
- userId);
+ ps = getPackageShortcutsForPublisherLocked(packageName, userId);
ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true);
ps.ensureNoBitmapIconIfShortcutIsLongLived(newShortcuts);
@@ -2097,8 +2119,7 @@ public class ShortcutService extends IShortcutService.Stub {
// Lastly, adjust the ranks.
ps.adjustRanks();
}
- packageShortcutsChanged(packageName, userId,
- changedShortcuts.isEmpty() ? null : changedShortcuts, null);
+ packageShortcutsChanged(ps, changedShortcuts.isEmpty() ? null : changedShortcuts, null);
verifyStates();
@@ -2118,12 +2139,12 @@ public class ShortcutService extends IShortcutService.Stub {
final int size = newShortcuts.size();
List<ShortcutInfo> changedShortcuts = null;
+ final ShortcutPackage ps;
synchronized (mLock) {
throwIfUserLockedL(userId);
- final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName,
- userId);
+ ps = getPackageShortcutsForPublisherLocked(packageName, userId);
ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true);
ps.ensureNoBitmapIconIfShortcutIsLongLived(newShortcuts);
@@ -2162,7 +2183,7 @@ public class ShortcutService extends IShortcutService.Stub {
// Lastly, adjust the ranks.
ps.adjustRanks();
}
- packageShortcutsChanged(packageName, userId, changedShortcuts, null);
+ packageShortcutsChanged(ps, changedShortcuts, null);
verifyStates();
return true;
}
@@ -2175,12 +2196,12 @@ public class ShortcutService extends IShortcutService.Stub {
List<ShortcutInfo> changedShortcuts = new ArrayList<>();
List<ShortcutInfo> removedShortcuts = null;
+ final ShortcutPackage ps;
synchronized (mLock) {
throwIfUserLockedL(userId);
- final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName,
- userId);
+ ps = getPackageShortcutsForPublisherLocked(packageName, userId);
ps.ensureNotImmutable(shortcut.getId(), /*ignoreInvisible=*/ true);
fillInDefaultActivity(Arrays.asList(shortcut));
@@ -2215,7 +2236,7 @@ public class ShortcutService extends IShortcutService.Stub {
ps.adjustRanks();
}
- packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
+ packageShortcutsChanged(ps, changedShortcuts, removedShortcuts);
reportShortcutUsedInternal(packageName, shortcut.getId(), userId);
@@ -2292,8 +2313,7 @@ public class ShortcutService extends IShortcutService.Stub {
ps.updateInvisibleShortcutForPinRequestWith(shortcut);
- packageShortcutsChanged(shortcutPackage, userId,
- Collections.singletonList(shortcut), null);
+ packageShortcutsChanged(ps, Collections.singletonList(shortcut), null);
}
}
@@ -2314,9 +2334,10 @@ public class ShortcutService extends IShortcutService.Stub {
Objects.requireNonNull(shortcutIds, "shortcutIds must be provided");
List<ShortcutInfo> changedShortcuts = null;
List<ShortcutInfo> removedShortcuts = null;
+ final ShortcutPackage ps;
synchronized (mLock) {
throwIfUserLockedL(userId);
- final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
+ ps = getPackageShortcutsForPublisherLocked(packageName, userId);
ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds,
/*ignoreInvisible=*/ true);
final String disabledMessageString =
@@ -2345,7 +2366,7 @@ public class ShortcutService extends IShortcutService.Stub {
// We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
ps.adjustRanks();
}
- packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
+ packageShortcutsChanged(ps, changedShortcuts, removedShortcuts);
verifyStates();
}
@@ -2354,9 +2375,10 @@ public class ShortcutService extends IShortcutService.Stub {
verifyCaller(packageName, userId);
Objects.requireNonNull(shortcutIds, "shortcutIds must be provided");
List<ShortcutInfo> changedShortcuts = null;
+ final ShortcutPackage ps;
synchronized (mLock) {
throwIfUserLockedL(userId);
- final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
+ ps = getPackageShortcutsForPublisherLocked(packageName, userId);
ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds,
/*ignoreInvisible=*/ true);
for (int i = shortcutIds.size() - 1; i >= 0; i--) {
@@ -2371,7 +2393,7 @@ public class ShortcutService extends IShortcutService.Stub {
changedShortcuts.add(ps.findShortcutById(id));
}
}
- packageShortcutsChanged(packageName, userId, changedShortcuts, null);
+ packageShortcutsChanged(ps, changedShortcuts, null);
verifyStates();
}
@@ -2383,11 +2405,10 @@ public class ShortcutService extends IShortcutService.Stub {
Objects.requireNonNull(shortcutIds, "shortcutIds must be provided");
List<ShortcutInfo> changedShortcuts = null;
List<ShortcutInfo> removedShortcuts = null;
-
+ final ShortcutPackage ps;
synchronized (mLock) {
throwIfUserLockedL(userId);
- final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName,
- userId);
+ ps = getPackageShortcutsForPublisherLocked(packageName, userId);
ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds,
/*ignoreInvisible=*/ true);
for (int i = shortcutIds.size() - 1; i >= 0; i--) {
@@ -2413,7 +2434,7 @@ public class ShortcutService extends IShortcutService.Stub {
// We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
ps.adjustRanks();
}
- packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
+ packageShortcutsChanged(ps, changedShortcuts, removedShortcuts);
verifyStates();
}
@@ -2422,10 +2443,10 @@ public class ShortcutService extends IShortcutService.Stub {
verifyCaller(packageName, userId);
List<ShortcutInfo> changedShortcuts = new ArrayList<>();
List<ShortcutInfo> removedShortcuts = null;
+ final ShortcutPackage ps;
synchronized (mLock) {
throwIfUserLockedL(userId);
- final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName,
- userId);
+ ps = getPackageShortcutsForPublisherLocked(packageName, userId);
// Dynamic shortcuts that are either cached or pinned will not get deleted.
ps.findAll(changedShortcuts,
(ShortcutInfo si) -> si.isVisibleToPublisher()
@@ -2435,7 +2456,7 @@ public class ShortcutService extends IShortcutService.Stub {
changedShortcuts = prepareChangedShortcuts(
changedShortcuts, null, removedShortcuts, ps);
}
- packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
+ packageShortcutsChanged(ps, changedShortcuts, removedShortcuts);
verifyStates();
}
@@ -2446,9 +2467,10 @@ public class ShortcutService extends IShortcutService.Stub {
Objects.requireNonNull(shortcutIds, "shortcutIds must be provided");
List<ShortcutInfo> changedShortcuts = null;
List<ShortcutInfo> removedShortcuts = null;
+ final ShortcutPackage ps;
synchronized (mLock) {
throwIfUserLockedL(userId);
- final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
+ ps = getPackageShortcutsForPublisherLocked(packageName, userId);
ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds,
/*ignoreInvisible=*/ true);
for (int i = shortcutIds.size() - 1; i >= 0; i--) {
@@ -2472,7 +2494,7 @@ public class ShortcutService extends IShortcutService.Stub {
// We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
ps.adjustRanks();
}
- packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
+ packageShortcutsChanged(ps, changedShortcuts, removedShortcuts);
verifyStates();
}
@@ -3113,7 +3135,7 @@ public class ShortcutService extends IShortcutService.Stub {
List<ShortcutInfo> changedShortcuts = null;
List<ShortcutInfo> removedShortcuts = null;
-
+ final ShortcutPackage sp;
synchronized (mLock) {
throwIfUserLockedL(userId);
throwIfUserLockedL(launcherUserId);
@@ -3122,8 +3144,7 @@ public class ShortcutService extends IShortcutService.Stub {
getLauncherShortcutsLocked(callingPackage, userId, launcherUserId);
launcher.attemptToRestoreIfNeededAndSave();
- final ShortcutPackage sp = getUserShortcutsLocked(userId)
- .getPackageShortcutsIfExists(packageName);
+ sp = getUserShortcutsLocked(userId).getPackageShortcutsIfExists(packageName);
if (sp != null) {
// List the shortcuts that are pinned only, these will get removed.
removedShortcuts = new ArrayList<>();
@@ -3147,7 +3168,9 @@ public class ShortcutService extends IShortcutService.Stub {
oldPinnedIds, new ArraySet<>(shortcutIds), removedShortcuts, sp);
}
- packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
+ if (sp != null) {
+ packageShortcutsChanged(sp, changedShortcuts, removedShortcuts);
+ }
verifyStates();
}
@@ -3198,14 +3221,13 @@ public class ShortcutService extends IShortcutService.Stub {
List<ShortcutInfo> changedShortcuts = null;
List<ShortcutInfo> removedShortcuts = null;
-
+ final ShortcutPackage sp;
synchronized (mLock) {
throwIfUserLockedL(userId);
throwIfUserLockedL(launcherUserId);
final int idSize = shortcutIds.size();
- final ShortcutPackage sp = getUserShortcutsLocked(userId)
- .getPackageShortcutsIfExists(packageName);
+ sp = getUserShortcutsLocked(userId).getPackageShortcutsIfExists(packageName);
if (idSize == 0 || sp == null) {
return;
}
@@ -3248,7 +3270,7 @@ public class ShortcutService extends IShortcutService.Stub {
}
}
}
- packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
+ packageShortcutsChanged(sp, changedShortcuts, removedShortcuts);
verifyStates();
}
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index a991ed3c4792..8c6b19b3361c 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -42,15 +42,19 @@ import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.policy.AttributeCache;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import java.io.File;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -61,6 +65,9 @@ public final class StorageEventHelper extends StorageEventListener {
private final DeletePackageHelper mDeletePackageHelper;
private final RemovePackageHelper mRemovePackageHelper;
+ @GuardedBy("mLoadedVolumes")
+ final ArraySet<String> mLoadedVolumes = new ArraySet<>();
+
// TODO(b/198166813): remove PMS dependency
public StorageEventHelper(PackageManagerService pm, DeletePackageHelper deletePackageHelper,
RemovePackageHelper removePackageHelper) {
@@ -216,8 +223,8 @@ public final class StorageEventHelper extends StorageEventListener {
if (DEBUG_INSTALL) Slog.d(TAG, "Loaded packages " + loaded);
sendResourcesChangedBroadcast(true, false, loaded, null);
- synchronized (mPm.mLoadedVolumes) {
- mPm.mLoadedVolumes.add(vol.getId());
+ synchronized (mLoadedVolumes) {
+ mLoadedVolumes.add(vol.getId());
}
}
@@ -267,8 +274,8 @@ public final class StorageEventHelper extends StorageEventListener {
if (DEBUG_INSTALL) Slog.d(TAG, "Unloaded packages " + unloaded);
sendResourcesChangedBroadcast(false, false, unloaded, null);
- synchronized (mPm.mLoadedVolumes) {
- mPm.mLoadedVolumes.remove(vol.getId());
+ synchronized (mLoadedVolumes) {
+ mLoadedVolumes.remove(vol.getId());
}
// Try very hard to release any references to this path so we don't risk
@@ -357,4 +364,24 @@ public final class StorageEventHelper extends StorageEventListener {
}
return codePaths;
}
+
+ public void dumpLoadedVolumes(@NonNull PrintWriter pw, @NonNull DumpState dumpState) {
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ ipw.println();
+ ipw.println("Loaded volumes:");
+ ipw.increaseIndent();
+ synchronized (mLoadedVolumes) {
+ if (mLoadedVolumes.size() == 0) {
+ ipw.println("(none)");
+ } else {
+ for (int i = 0; i < mLoadedVolumes.size(); i++) {
+ ipw.println(mLoadedVolumes.valueAt(i));
+ }
+ }
+ }
+ ipw.decreaseIndent();
+ }
}
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index 588dfaf6db78..860c54c31bb2 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -16,10 +16,6 @@
package com.android.server.pm;
-import static android.content.pm.PackageManagerInternal.PACKAGE_INSTALLER;
-import static android.content.pm.PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER;
-import static android.content.pm.PackageManagerInternal.PACKAGE_UNINSTALLER;
-import static android.content.pm.PackageManagerInternal.PACKAGE_VERIFIER;
import static android.os.Process.SYSTEM_UID;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
@@ -31,7 +27,6 @@ import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.Intent;
-import android.content.pm.PackageManagerInternal.KnownPackage;
import android.content.pm.SuspendDialogInfo;
import android.os.Binder;
import android.os.Bundle;
@@ -489,13 +484,14 @@ public final class SuspendPackageHelper {
final String activeLauncherPackageName = defaultAppProvider.getDefaultHome(userId);
final String dialerPackageName = defaultAppProvider.getDefaultDialer(userId);
final String requiredInstallerPackage =
- getKnownPackageName(snapshot, PACKAGE_INSTALLER, userId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_INSTALLER, userId);
final String requiredUninstallerPackage =
- getKnownPackageName(snapshot, PACKAGE_UNINSTALLER, userId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_UNINSTALLER, userId);
final String requiredVerifierPackage =
- getKnownPackageName(snapshot, PACKAGE_VERIFIER, userId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_VERIFIER, userId);
final String requiredPermissionControllerPackage =
- getKnownPackageName(snapshot, PACKAGE_PERMISSION_CONTROLLER, userId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_PERMISSION_CONTROLLER,
+ userId);
for (int i = 0; i < packageNames.length; i++) {
canSuspend[i] = false;
final String packageName = packageNames[i];
@@ -638,8 +634,8 @@ public final class SuspendPackageHelper {
}
}
- private String getKnownPackageName(@NonNull Computer snapshot, @KnownPackage int knownPackage,
- int userId) {
+ private String getKnownPackageName(@NonNull Computer snapshot,
+ @KnownPackages.KnownPackage int knownPackage, int userId) {
final String[] knownPackages =
mPm.getKnownPackageNamesInternal(snapshot, knownPackage, userId);
return knownPackages.length > 0 ? knownPackages[0] : null;
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 9bcb7242b645..016c1cb7bdf0 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -27,6 +27,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Binder;
import android.os.Bundle;
import android.os.Process;
@@ -678,21 +679,9 @@ public class UserRestrictionsUtils {
break;
case UserManager.DISALLOW_AMBIENT_DISPLAY:
if (newValue) {
- android.provider.Settings.Secure.putIntForUser(
- context.getContentResolver(),
- Settings.Secure.DOZE_ENABLED, 0, userId);
- android.provider.Settings.Secure.putIntForUser(
- context.getContentResolver(),
- Settings.Secure.DOZE_ALWAYS_ON, 0, userId);
- android.provider.Settings.Secure.putIntForUser(
- context.getContentResolver(),
- Settings.Secure.DOZE_PICK_UP_GESTURE, 0, userId);
- android.provider.Settings.Secure.putIntForUser(
- context.getContentResolver(),
- Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, 0, userId);
- android.provider.Settings.Secure.putIntForUser(
- context.getContentResolver(),
- Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, 0, userId);
+ final AmbientDisplayConfiguration config =
+ new AmbientDisplayConfiguration(context);
+ config.disableDozeSettings(userId);
}
break;
case UserManager.DISALLOW_APPS_CONTROL:
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 36633cc635e7..849f53026c99 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -70,6 +70,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
+import com.android.server.pm.KnownPackages;
import com.android.server.pm.permission.LegacyPermissionManagerInternal.PackagesProvider;
import com.android.server.pm.permission.LegacyPermissionManagerInternal.SyncAdapterPackagesProvider;
@@ -585,19 +586,19 @@ final class DefaultPermissionGrantPolicy {
// Installer
grantSystemFixedPermissionsToSystemPackage(pm,
ArrayUtils.firstOrNull(getKnownPackages(
- PackageManagerInternal.PACKAGE_INSTALLER, userId)),
+ KnownPackages.PACKAGE_INSTALLER, userId)),
userId, STORAGE_PERMISSIONS, NOTIFICATION_PERMISSIONS);
// Verifier
final String verifier = ArrayUtils.firstOrNull(getKnownPackages(
- PackageManagerInternal.PACKAGE_VERIFIER, userId));
+ KnownPackages.PACKAGE_VERIFIER, userId));
grantSystemFixedPermissionsToSystemPackage(pm, verifier, userId, STORAGE_PERMISSIONS);
grantPermissionsToSystemPackage(pm, verifier, userId, PHONE_PERMISSIONS, SMS_PERMISSIONS,
NOTIFICATION_PERMISSIONS);
// SetupWizard
final String setupWizardPackage = ArrayUtils.firstOrNull(getKnownPackages(
- PackageManagerInternal.PACKAGE_SETUP_WIZARD, userId));
+ KnownPackages.PACKAGE_SETUP_WIZARD, userId));
grantPermissionsToSystemPackage(pm, setupWizardPackage, userId, PHONE_PERMISSIONS,
CONTACTS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS, CAMERA_PERMISSIONS);
grantSystemFixedPermissionsToSystemPackage(pm, setupWizardPackage, userId,
@@ -758,7 +759,7 @@ final class DefaultPermissionGrantPolicy {
// Browser
String browserPackage = ArrayUtils.firstOrNull(getKnownPackages(
- PackageManagerInternal.PACKAGE_BROWSER, userId));
+ KnownPackages.PACKAGE_BROWSER, userId));
if (browserPackage == null) {
browserPackage = getDefaultSystemHandlerActivityPackageForCategory(pm,
Intent.CATEGORY_APP_BROWSER, userId);
@@ -890,7 +891,7 @@ final class DefaultPermissionGrantPolicy {
// TextClassifier Service
for (String textClassifierPackage :
- getKnownPackages(PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER, userId)) {
+ getKnownPackages(KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER, userId)) {
grantPermissionsToSystemPackage(pm, textClassifierPackage, userId,
COARSE_BACKGROUND_LOCATION_PERMISSIONS, CONTACTS_PERMISSIONS);
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 009d155e96ef..c524fb7ae9e5 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -126,6 +126,7 @@ import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
import com.android.server.pm.ApexManager;
+import com.android.server.pm.KnownPackages;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.parsing.PackageInfoUtils;
@@ -3323,7 +3324,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
@NonNull Permission bp) {
// expect single system package
String systemPackageName = ArrayUtils.firstOrNull(mPackageManagerInt.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM));
+ KnownPackages.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM));
final AndroidPackage systemPackage =
mPackageManagerInt.getPackage(systemPackageName);
// check if the package is allow to use this signature permission. A package is allowed to
@@ -3398,10 +3399,10 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
// permissions are needed by the permission controller
if (!allowed && bp.isInstaller()
&& (ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM),
+ KnownPackages.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM),
pkg.getPackageName()) || ArrayUtils.contains(
mPackageManagerInt.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER,
+ KnownPackages.PACKAGE_PERMISSION_CONTROLLER,
UserHandle.USER_SYSTEM), pkg.getPackageName()))) {
// If this permission is to be granted to the system installer and
// this app is an installer, then it gets the permission.
@@ -3409,7 +3410,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
if (!allowed && bp.isVerifier()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM),
+ KnownPackages.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM),
pkg.getPackageName())) {
// If this permission is to be granted to the system verifier and
// this app is a verifier, then it gets the permission.
@@ -3433,7 +3434,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
//}
if (!allowed && bp.isSetup()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM),
+ KnownPackages.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM),
pkg.getPackageName())) {
// If this permission is to be granted to the system setup wizard and
// this app is a setup wizard, then it gets the permission.
@@ -3441,21 +3442,21 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
if (!allowed && bp.isSystemTextClassifier()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER,
+ KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER,
UserHandle.USER_SYSTEM), pkg.getPackageName())) {
// Special permissions for the system default text classifier.
allowed = true;
}
if (!allowed && bp.isConfigurator()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_CONFIGURATOR,
+ KnownPackages.PACKAGE_CONFIGURATOR,
UserHandle.USER_SYSTEM), pkg.getPackageName())) {
// Special permissions for the device configurator.
allowed = true;
}
if (!allowed && bp.isIncidentReportApprover()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER,
+ KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER,
UserHandle.USER_SYSTEM), pkg.getPackageName())) {
// If this permission is to be granted to the incident report approver and
// this app is the incident report approver, then it gets the permission.
@@ -3463,28 +3464,28 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
if (!allowed && bp.isAppPredictor()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_APP_PREDICTOR, UserHandle.USER_SYSTEM),
+ KnownPackages.PACKAGE_APP_PREDICTOR, UserHandle.USER_SYSTEM),
pkg.getPackageName())) {
// Special permissions for the system app predictor.
allowed = true;
}
if (!allowed && bp.isCompanion()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_COMPANION, UserHandle.USER_SYSTEM),
+ KnownPackages.PACKAGE_COMPANION, UserHandle.USER_SYSTEM),
pkg.getPackageName())) {
// Special permissions for the system companion device manager.
allowed = true;
}
if (!allowed && bp.isRetailDemo()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_RETAIL_DEMO, UserHandle.USER_SYSTEM),
+ KnownPackages.PACKAGE_RETAIL_DEMO, UserHandle.USER_SYSTEM),
pkg.getPackageName()) && isProfileOwner(pkg.getUid())) {
// Special permission granted only to the OEM specified retail demo app
allowed = true;
}
if (!allowed && bp.isRecents()
&& ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_RECENTS, UserHandle.USER_SYSTEM),
+ KnownPackages.PACKAGE_RECENTS, UserHandle.USER_SYSTEM),
pkg.getPackageName())) {
// Special permission for the recents app.
allowed = true;
diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
index cf9370d12735..9aa53f18d0aa 100644
--- a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
@@ -47,13 +47,11 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.server.IntentResolver;
import com.android.server.pm.Computer;
-import com.android.server.pm.DumpState;
import com.android.server.pm.PackageManagerException;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.UserNeedsBadgingCache;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageStateUtils;
import com.android.server.pm.pkg.PackageUserStateInternal;
@@ -76,7 +74,6 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
@@ -271,119 +268,6 @@ public class ComponentResolver extends ComponentResolverLocked implements Snappa
}
}
- public void dumpActivityResolvers(PrintWriter pw, DumpState dumpState, String packageName) {
- synchronized (mLock) {
- if (mActivities.dump(pw, dumpState.getTitlePrinted() ? "\nActivity Resolver Table:"
- : "Activity Resolver Table:", " ", packageName,
- dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
- dumpState.setTitlePrinted(true);
- }
- }
- }
-
- public void dumpProviderResolvers(PrintWriter pw, DumpState dumpState, String packageName) {
- synchronized (mLock) {
- if (mProviders.dump(pw, dumpState.getTitlePrinted() ? "\nProvider Resolver Table:"
- : "Provider Resolver Table:", " ", packageName,
- dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
- dumpState.setTitlePrinted(true);
- }
- }
- }
-
- public void dumpReceiverResolvers(PrintWriter pw, DumpState dumpState, String packageName) {
- synchronized (mLock) {
- if (mReceivers.dump(pw, dumpState.getTitlePrinted() ? "\nReceiver Resolver Table:"
- : "Receiver Resolver Table:", " ", packageName,
- dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
- dumpState.setTitlePrinted(true);
- }
- }
- }
-
- public void dumpServiceResolvers(PrintWriter pw, DumpState dumpState, String packageName) {
- synchronized (mLock) {
- if (mServices.dump(pw, dumpState.getTitlePrinted() ? "\nService Resolver Table:"
- : "Service Resolver Table:", " ", packageName,
- dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
- dumpState.setTitlePrinted(true);
- }
- }
- }
-
- public void dumpContentProviders(@NonNull Computer computer, PrintWriter pw,
- DumpState dumpState, String packageName) {
- synchronized (mLock) {
- boolean printedSomething = false;
- for (ParsedProvider p : mProviders.mProviders.values()) {
- if (packageName != null && !packageName.equals(p.getPackageName())) {
- continue;
- }
- if (!printedSomething) {
- if (dumpState.onTitlePrinted()) {
- pw.println();
- }
- pw.println("Registered ContentProviders:");
- printedSomething = true;
- }
- pw.print(" ");
- ComponentName.printShortString(pw, p.getPackageName(), p.getName());
- pw.println(":");
- pw.print(" ");
- pw.println(p.toString());
- }
- printedSomething = false;
- for (Map.Entry<String, ParsedProvider> entry :
- mProvidersByAuthority.entrySet()) {
- ParsedProvider p = entry.getValue();
- if (packageName != null && !packageName.equals(p.getPackageName())) {
- continue;
- }
- if (!printedSomething) {
- if (dumpState.onTitlePrinted()) {
- pw.println();
- }
- pw.println("ContentProvider Authorities:");
- printedSomething = true;
- }
- pw.print(" [");
- pw.print(entry.getKey());
- pw.println("]:");
- pw.print(" ");
- pw.println(p.toString());
-
- AndroidPackage pkg = computer.getPackage(p.getPackageName());
-
- if (pkg != null) {
- pw.print(" applicationInfo=");
- pw.println(AndroidPackageUtils.generateAppInfoWithoutState(pkg));
- }
- }
- }
- }
-
- public void dumpServicePermissions(PrintWriter pw, DumpState dumpState) {
- synchronized (mLock) {
- if (dumpState.onTitlePrinted()) pw.println();
- pw.println("Service permissions:");
-
- final Iterator<Pair<ParsedService, ParsedIntentInfo>> filterIterator =
- mServices.filterIterator();
- while (filterIterator.hasNext()) {
- final Pair<ParsedService, ParsedIntentInfo> pair = filterIterator.next();
- ParsedService service = pair.first;
-
- final String permission = service.getPermission();
- if (permission != null) {
- pw.print(" ");
- pw.print(service.getComponentName().flattenToShortString());
- pw.print(": ");
- pw.println(permission);
- }
- }
- }
- }
-
@GuardedBy("mLock")
private void addActivitiesLocked(@NonNull Computer computer, AndroidPackage pkg,
List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents, boolean chatty) {
diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolverApi.java b/services/core/java/com/android/server/pm/resolution/ComponentResolverApi.java
index b6f2b2a0451b..b8e4c8d2a51f 100644
--- a/services/core/java/com/android/server/pm/resolution/ComponentResolverApi.java
+++ b/services/core/java/com/android/server/pm/resolution/ComponentResolverApi.java
@@ -26,10 +26,12 @@ import android.content.pm.ResolveInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.Computer;
+import com.android.server.pm.DumpState;
import com.android.server.pm.pkg.component.ParsedActivity;
import com.android.server.pm.pkg.component.ParsedProvider;
import com.android.server.pm.pkg.component.ParsedService;
+import java.io.PrintWriter;
import java.util.List;
public interface ComponentResolverApi {
@@ -97,4 +99,21 @@ public interface ComponentResolverApi {
void querySyncProviders(@NonNull Computer computer, @NonNull List<String> outNames,
@NonNull List<ProviderInfo> outInfo, boolean safeMode, @UserIdInt int userId);
+
+ void dumpActivityResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState,
+ @NonNull String packageName);
+
+ void dumpProviderResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState,
+ @NonNull String packageName);
+
+ void dumpReceiverResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState,
+ @NonNull String packageName);
+
+ void dumpServiceResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState,
+ @NonNull String packageName);
+
+ void dumpContentProviders(@NonNull Computer computer, @NonNull PrintWriter pw,
+ @NonNull DumpState dumpState, @NonNull String packageName);
+
+ void dumpServicePermissions(@NonNull PrintWriter pw, @NonNull DumpState dumpState);
}
diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java b/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java
index 6b50fc6d306d..c01cecff9f61 100644
--- a/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java
+++ b/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java
@@ -26,21 +26,28 @@ import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.Pair;
import com.android.server.pm.Computer;
+import com.android.server.pm.DumpState;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageUserStateInternal;
import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
import com.android.server.pm.pkg.component.ParsedMainComponent;
import com.android.server.pm.pkg.component.ParsedProvider;
import com.android.server.pm.pkg.component.ParsedService;
import com.android.server.utils.WatchableImpl;
+import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
public abstract class ComponentResolverBase extends WatchableImpl implements ComponentResolverApi {
@@ -305,4 +312,116 @@ public abstract class ComponentResolverBase extends WatchableImpl implements Com
outInfo.add(info);
}
}
+
+ @Override
+ public void dumpActivityResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState,
+ @NonNull String packageName) {
+ if (mActivities.dump(pw, dumpState.getTitlePrinted() ? "\nActivity Resolver Table:"
+ : "Activity Resolver Table:", " ", packageName,
+ dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
+ dumpState.setTitlePrinted(true);
+ }
+ }
+
+ @Override
+ public void dumpProviderResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState,
+ @NonNull String packageName) {
+ if (mProviders.dump(pw, dumpState.getTitlePrinted() ? "\nProvider Resolver Table:"
+ : "Provider Resolver Table:", " ", packageName,
+ dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
+ dumpState.setTitlePrinted(true);
+ }
+ }
+
+ @Override
+ public void dumpReceiverResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState,
+ @NonNull String packageName) {
+ if (mReceivers.dump(pw, dumpState.getTitlePrinted() ? "\nReceiver Resolver Table:"
+ : "Receiver Resolver Table:", " ", packageName,
+ dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
+ dumpState.setTitlePrinted(true);
+ }
+ }
+
+ @Override
+ public void dumpServiceResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState,
+ @NonNull String packageName) {
+ if (mServices.dump(pw, dumpState.getTitlePrinted() ? "\nService Resolver Table:"
+ : "Service Resolver Table:", " ", packageName,
+ dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
+ dumpState.setTitlePrinted(true);
+ }
+ }
+
+ @Override
+ public void dumpContentProviders(@NonNull Computer computer, @NonNull PrintWriter pw,
+ @NonNull DumpState dumpState, @NonNull String packageName) {
+ boolean printedSomething = false;
+ for (ParsedProvider p : mProviders.mProviders.values()) {
+ if (packageName != null && !packageName.equals(p.getPackageName())) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
+ pw.println("Registered ContentProviders:");
+ printedSomething = true;
+ }
+ pw.print(" ");
+ ComponentName.printShortString(pw, p.getPackageName(), p.getName());
+ pw.println(":");
+ pw.print(" ");
+ pw.println(p.toString());
+ }
+ printedSomething = false;
+ for (Map.Entry<String, ParsedProvider> entry :
+ mProvidersByAuthority.entrySet()) {
+ ParsedProvider p = entry.getValue();
+ if (packageName != null && !packageName.equals(p.getPackageName())) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
+ pw.println("ContentProvider Authorities:");
+ printedSomething = true;
+ }
+ pw.print(" [");
+ pw.print(entry.getKey());
+ pw.println("]:");
+ pw.print(" ");
+ pw.println(p.toString());
+
+ AndroidPackage pkg = computer.getPackage(p.getPackageName());
+
+ if (pkg != null) {
+ pw.print(" applicationInfo=");
+ pw.println(AndroidPackageUtils.generateAppInfoWithoutState(pkg));
+ }
+ }
+ }
+
+ @Override
+ public void dumpServicePermissions(@NonNull PrintWriter pw, @NonNull DumpState dumpState) {
+ if (dumpState.onTitlePrinted()) pw.println();
+ pw.println("Service permissions:");
+
+ final Iterator<Pair<ParsedService, ParsedIntentInfo>> filterIterator =
+ mServices.filterIterator();
+ while (filterIterator.hasNext()) {
+ final Pair<ParsedService, ParsedIntentInfo> pair = filterIterator.next();
+ ParsedService service = pair.first;
+
+ final String permission = service.getPermission();
+ if (permission != null) {
+ pw.print(" ");
+ pw.print(service.getComponentName().flattenToShortString());
+ pw.print(": ");
+ pw.println(permission);
+ }
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolverLocked.java b/services/core/java/com/android/server/pm/resolution/ComponentResolverLocked.java
index ecc53ebf3d10..0c84f4c53dfe 100644
--- a/services/core/java/com/android/server/pm/resolution/ComponentResolverLocked.java
+++ b/services/core/java/com/android/server/pm/resolution/ComponentResolverLocked.java
@@ -25,12 +25,14 @@ import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import com.android.server.pm.Computer;
+import com.android.server.pm.DumpState;
import com.android.server.pm.PackageManagerTracedLock;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.pkg.component.ParsedActivity;
import com.android.server.pm.pkg.component.ParsedProvider;
import com.android.server.pm.pkg.component.ParsedService;
+import java.io.PrintWriter;
import java.util.List;
public abstract class ComponentResolverLocked extends ComponentResolverBase {
@@ -189,4 +191,51 @@ public abstract class ComponentResolverLocked extends ComponentResolverBase {
super.querySyncProviders(computer, outNames, outInfo, safeMode, userId);
}
}
+
+ @Override
+ public void dumpActivityResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState,
+ @NonNull String packageName) {
+ synchronized (mLock) {
+ super.dumpActivityResolvers(pw, dumpState, packageName);
+ }
+ }
+
+ @Override
+ public void dumpProviderResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState,
+ @NonNull String packageName) {
+ synchronized (mLock) {
+ super.dumpProviderResolvers(pw, dumpState, packageName);
+ }
+ }
+
+ @Override
+ public void dumpReceiverResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState,
+ @NonNull String packageName) {
+ synchronized (mLock) {
+ super.dumpReceiverResolvers(pw, dumpState, packageName);
+ }
+ }
+
+ @Override
+ public void dumpServiceResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState,
+ @NonNull String packageName) {
+ synchronized (mLock) {
+ super.dumpServiceResolvers(pw, dumpState, packageName);
+ }
+ }
+
+ @Override
+ public void dumpContentProviders(@NonNull Computer computer, @NonNull PrintWriter pw,
+ @NonNull DumpState dumpState, @NonNull String packageName) {
+ synchronized (mLock) {
+ super.dumpContentProviders(computer, pw, dumpState, packageName);
+ }
+ }
+
+ @Override
+ public void dumpServicePermissions(@NonNull PrintWriter pw, @NonNull DumpState dumpState) {
+ synchronized (mLock) {
+ super.dumpServicePermissions(pw, dumpState);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 11cb5a7167dc..e8546a768429 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -17,6 +17,7 @@
package com.android.server.policy;
import static android.Manifest.permission.POST_NOTIFICATIONS;
+import static android.app.ActivityOptions.ANIM_REMOTE_ANIMATION;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_FOREGROUND;
import static android.app.AppOpsManager.MODE_IGNORED;
@@ -58,8 +59,6 @@ import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PermissionInfo;
import android.os.Build;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -93,6 +92,7 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.wm.ActivityInterceptorCallback;
+import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo;
import com.android.server.wm.ActivityTaskManagerInternal;
import java.util.ArrayList;
@@ -115,7 +115,6 @@ public final class PermissionPolicyService extends SystemService {
private static final String SYSTEM_PKG = "android";
private static final boolean DEBUG = false;
private static final long USER_SENSITIVE_UPDATE_DELAY_MS = 60000;
- private static final long ACTIVITY_START_DELAY_MS = 200;
private final Object mLock = new Object();
@@ -155,8 +154,7 @@ public final class PermissionPolicyService extends SystemService {
private List<String> mAppOpPermissions;
- private final Context mContext;
- private final Handler mHandler;
+ private Context mContext;
private PackageManagerInternal mPackageManagerInternal;
private PermissionManagerServiceInternal mPermissionManagerInternal;
private NotificationManagerInternal mNotificationManager;
@@ -167,7 +165,6 @@ public final class PermissionPolicyService extends SystemService {
super(context);
mContext = context;
- mHandler = new Handler(Looper.getMainLooper());
mPackageManager = context.getPackageManager();
mKeyguardManager = context.getSystemService(KeyguardManager.class);
LocalServices.addService(PermissionPolicyInternal.class, new Internal());
@@ -1072,7 +1069,7 @@ public final class PermissionPolicyService extends SystemService {
clearNotificationReviewFlagsIfNeeded(activityInfo.packageName, user);
} else {
showNotificationPromptIfNeeded(activityInfo.packageName,
- taskInfo.userId, taskInfo.taskId);
+ taskInfo.userId, taskInfo.taskId, info);
}
}
};
@@ -1103,15 +1100,21 @@ public final class PermissionPolicyService extends SystemService {
return true;
}
+ @Override
public void showNotificationPromptIfNeeded(@NonNull String packageName, int userId,
int taskId) {
+ showNotificationPromptIfNeeded(packageName, userId, taskId, null /* info */);
+ }
+
+ void showNotificationPromptIfNeeded(@NonNull String packageName, int userId,
+ int taskId, @Nullable ActivityInterceptorInfo info) {
UserHandle user = UserHandle.of(userId);
if (packageName == null || taskId == ActivityTaskManager.INVALID_TASK_ID
|| !shouldForceShowNotificationPermissionRequest(packageName, user)) {
return;
}
- launchNotificationPermissionRequestDialog(packageName, user, taskId);
+ launchNotificationPermissionRequestDialog(packageName, user, taskId, info);
}
@Override
@@ -1180,7 +1183,7 @@ public final class PermissionPolicyService extends SystemService {
}
private void launchNotificationPermissionRequestDialog(String pkgName, UserHandle user,
- int taskId) {
+ int taskId, @Nullable ActivityInterceptorInfo info) {
Intent grantPermission = mPackageManager
.buildRequestPermissionsIntent(new String[] { POST_NOTIFICATIONS });
// Prevent the front-most activity entering pip due to overlay activity started on top.
@@ -1189,18 +1192,29 @@ public final class PermissionPolicyService extends SystemService {
ACTION_REQUEST_PERMISSIONS_FOR_OTHER);
grantPermission.putExtra(Intent.EXTRA_PACKAGE_NAME, pkgName);
- ActivityOptions options = new ActivityOptions(new Bundle());
+ final boolean remoteAnimation = info != null && info.checkedOptions != null
+ && info.checkedOptions.getAnimationType() == ANIM_REMOTE_ANIMATION
+ && info.clearOptionsAnimation != null;
+ ActivityOptions options = remoteAnimation ? ActivityOptions.makeRemoteAnimation(
+ info.checkedOptions.getRemoteAnimationAdapter(),
+ info.checkedOptions.getRemoteTransition())
+ : new ActivityOptions(new Bundle());
options.setTaskOverlay(true, false);
options.setLaunchTaskId(taskId);
- mHandler.postDelayed(() -> {
- try {
- mContext.startActivityAsUser(
- grantPermission, options.toBundle(), user);
- } catch (Exception e) {
- Log.e(LOG_TAG, "couldn't start grant permission dialog"
- + "for other package " + pkgName, e);
- }
- }, ACTIVITY_START_DELAY_MS);
+ if (remoteAnimation) {
+ // Remote animation set on the intercepted activity will be handled by the grant
+ // permission activity, which is launched below. So we need to clear remote
+ // animation from the intercepted activity and its siblings to prevent duplication.
+ // This should trigger ActivityRecord#clearOptionsAnimationForSiblings for the
+ // intercepted activity.
+ info.clearOptionsAnimation.run();
+ }
+ try {
+ mContext.startActivityAsUser(grantPermission, options.toBundle(), user);
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "couldn't start grant permission dialog"
+ + "for other package " + pkgName, e);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 999428a5f35b..b14214189833 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4526,6 +4526,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Called on the PowerManager's Notifier thread.
@Override
+ public void onPowerGroupWakefulnessChanged(int groupId, int wakefulness,
+ @PowerManager.GoToSleepReason int pmSleepReason, int globalWakefulness) {
+ if (wakefulness != globalWakefulness
+ && wakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE
+ && groupId == Display.DEFAULT_DISPLAY_GROUP
+ && mKeyguardDelegate != null) {
+ mKeyguardDelegate.doKeyguardTimeout(null);
+ }
+ }
+
+ // Called on the PowerManager's Notifier thread.
+ @Override
public void startedWakingUp(@PowerManager.WakeReason int pmWakeReason) {
EventLogTags.writeScreenToggled(1);
if (DEBUG_WAKEUP) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 4571cf395287..7ca09ab5154f 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -773,6 +773,20 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public void finishedGoingToSleep(@PowerManager.GoToSleepReason int pmSleepReason);
/**
+ * Called when a particular PowerGroup has changed wakefulness.
+ *
+ * @param groupId The id of the PowerGroup.
+ * @param wakefulness One of PowerManagerInternal.WAKEFULNESS_* indicating the wake state for
+ * the group
+ * @param pmSleepReason One of PowerManager.GO_TO_SLEEP_REASON_*, detailing the reason this
+ * group is going to sleep.
+ * @param globalWakefulness The global wakefulness, which may or may not match that of this
+ * group. One of PowerManagerInternal.WAKEFULNESS_*
+ */
+ void onPowerGroupWakefulnessChanged(int groupId, int wakefulness,
+ @PowerManager.GoToSleepReason int pmSleepReason, int globalWakefulness);
+
+ /**
* Called when the display is about to turn on to show content.
* When waking up, this method will be called once after the call to wakingUp().
* When dozing, the method will be called sometime after the call to goingToSleep() and
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 77d63100032c..aede4b1e2f5d 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -553,6 +553,15 @@ public class Notifier {
}
/**
+ * Called when an individual PowerGroup changes wakefulness.
+ */
+ public void onPowerGroupWakefulnessChanged(int groupId, int groupWakefulness, int changeReason,
+ int globalWakefulness) {
+ mHandler.post(() -> mPolicy.onPowerGroupWakefulnessChanged(groupId, groupWakefulness,
+ changeReason, globalWakefulness));
+ }
+
+ /**
* Called when there has been user activity.
*/
public void onUserActivity(int displayGroupId, int event, int uid) {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index c04d6082877a..ad56f199c269 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -669,11 +669,17 @@ public final class PowerManagerService extends SystemService
int reason, int uid, int opUid, String opPackageName, String details) {
if (wakefulness == WAKEFULNESS_AWAKE) {
// Kick user activity to prevent newly awake group from timing out instantly.
+ // The dream may end without user activity if the dream app crashes / is updated,
+ // don't poke the user activity timer for these wakes.
+ int flags = reason == PowerManager.WAKE_REASON_DREAM_FINISHED
+ ? PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS : 0;
userActivityNoUpdateLocked(mPowerGroups.get(groupId), eventTime,
- PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
+ PowerManager.USER_ACTIVITY_EVENT_OTHER, flags, uid);
}
mDirty |= DIRTY_DISPLAY_GROUP_WAKEFULNESS;
updateGlobalWakefulnessLocked(eventTime, reason, uid, opUid, opPackageName, details);
+ mNotifier.onPowerGroupWakefulnessChanged(groupId, wakefulness, reason,
+ getGlobalWakefulnessLocked());
updatePowerStateLocked();
}
}
@@ -3190,7 +3196,7 @@ public final class PowerManagerService extends SystemService
wakefulness = powerGroup.getWakefulnessLocked();
if ((wakefulness == WAKEFULNESS_DREAMING || wakefulness == WAKEFULNESS_DOZING) &&
powerGroup.isSandmanSummonedLocked() && powerGroup.isReadyLocked()) {
- startDreaming = canDreamLocked(powerGroup) || canDozeLocked();
+ startDreaming = canDreamLocked(powerGroup) || canDozeLocked(powerGroup);
powerGroup.setSandmanSummonedLocked(/* isSandmanSummoned= */ false);
} else {
startDreaming = false;
@@ -3273,7 +3279,7 @@ public final class PowerManagerService extends SystemService
}
} else {
wakePowerGroupLocked(powerGroup, now,
- PowerManager.WAKE_REASON_UNKNOWN,
+ PowerManager.WAKE_REASON_DREAM_FINISHED,
"android.server.power:DREAM_FINISHED", Process.SYSTEM_UID,
mContext.getOpPackageName(), Process.SYSTEM_UID);
}
@@ -3329,9 +3335,9 @@ public final class PowerManagerService extends SystemService
* Returns true if the device is allowed to doze in its current state.
*/
@GuardedBy("mLock")
- private boolean canDozeLocked() {
- // TODO (b/175764708): Support per-display doze.
- return getGlobalWakefulnessLocked() == WAKEFULNESS_DOZING;
+ private boolean canDozeLocked(PowerGroup powerGroup) {
+ return powerGroup.supportsSandmanLocked()
+ && powerGroup.getWakefulnessLocked() == WAKEFULNESS_DOZING;
}
/**
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 8755662ac813..dfa12814a138 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -256,6 +256,10 @@ public final class HintManagerService extends SystemService {
@Override
public void onUidCachedChanged(int uid, boolean cached) {
}
+
+ @Override
+ public void onUidProcAdjChanged(int uid) {
+ }
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 526dccb72e39..5e7b5860629d 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1635,10 +1635,24 @@ public class StatsPullAtomService extends SystemService {
new SynchronousResultReceiver("bluetooth");
adapter.requestControllerActivityEnergyInfo(
Runnable::run,
- info -> {
- Bundle bundle = new Bundle();
- bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, info);
- bluetoothReceiver.send(0, bundle);
+ new BluetoothAdapter.OnBluetoothActivityEnergyInfoCallback() {
+ @Override
+ public void onBluetoothActivityEnergyInfoAvailable(
+ BluetoothActivityEnergyInfo info) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(
+ BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, info);
+ bluetoothReceiver.send(0, bundle);
+ }
+
+ @Override
+ public void onBluetoothActivityEnergyInfoError(int errorCode) {
+ Slog.w(TAG, "error reading Bluetooth stats: " + errorCode);
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(
+ BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, null);
+ bluetoothReceiver.send(0, bundle);
+ }
}
);
return awaitControllerInfo(bluetoothReceiver);
diff --git a/services/core/java/com/android/server/utils/WatchedArrayList.java b/services/core/java/com/android/server/utils/WatchedArrayList.java
index bb0ba1329d86..6059f9675e34 100644
--- a/services/core/java/com/android/server/utils/WatchedArrayList.java
+++ b/services/core/java/com/android/server/utils/WatchedArrayList.java
@@ -273,6 +273,13 @@ public class WatchedArrayList<E> extends WatchableImpl
}
/**
+ * Return true if all the objects in the given collection are in this array list.
+ */
+ public boolean containsAll(Collection<?> c) {
+ return mStorage.containsAll(c);
+ }
+
+ /**
* Ensure capacity.
*/
public void ensureCapacity(int min) {
diff --git a/services/core/java/com/android/server/utils/WatchedArraySet.java b/services/core/java/com/android/server/utils/WatchedArraySet.java
index 5070dd1675d3..ec80261a2196 100644
--- a/services/core/java/com/android/server/utils/WatchedArraySet.java
+++ b/services/core/java/com/android/server/utils/WatchedArraySet.java
@@ -20,6 +20,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.ArraySet;
+import java.util.Collection;
+
/**
* WatchedArraySet is an {@link android.util.ArraySet} that can report changes to itself. If its
* values are {@link Watchable} then the WatchedArraySet will also report changes to the values.
@@ -280,13 +282,11 @@ public class WatchedArraySet<E> extends WatchableImpl
/**
* Perform a {@link #add(Object)} of all values in <var>array</var>
- * @param array The array whose contents are to be retrieved.
+ * @param collection The collection whose contents are to be retrieved.
*/
- public void addAll(ArraySet<? extends E> array) {
- final int end = array.size();
- for (int i = 0; i < end; i++) {
- add(array.valueAt(i));
- }
+ public void addAll(Collection<? extends E> collection) {
+ mStorage.addAll(collection);
+ onChanged();
}
/**
diff --git a/services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java b/services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java
index 25ae00004b3e..c43e7f9babe6 100644
--- a/services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java
+++ b/services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java
@@ -18,6 +18,7 @@ package com.android.server.utils;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
@@ -168,12 +169,19 @@ public class WatchedSparseBooleanMatrix extends WatchableImpl implements Snappab
* A copy constructor that can be used for snapshotting.
*/
private WatchedSparseBooleanMatrix(WatchedSparseBooleanMatrix r) {
- mOrder = r.mOrder;
- mSize = r.mSize;
- mKeys = r.mKeys.clone();
- mMap = r.mMap.clone();
- mInUse = r.mInUse.clone();
- mValues = r.mValues.clone();
+ copyFrom(r);
+ }
+
+ /**
+ * Copy from src to this.
+ */
+ public void copyFrom(@NonNull WatchedSparseBooleanMatrix src) {
+ mOrder = src.mOrder;
+ mSize = src.mSize;
+ mKeys = src.mKeys.clone();
+ mMap = src.mMap.clone();
+ mInUse = src.mInUse.clone();
+ mValues = src.mValues.clone();
}
/**
diff --git a/services/core/java/com/android/server/utils/WatchedSparseSetArray.java b/services/core/java/com/android/server/utils/WatchedSparseSetArray.java
new file mode 100644
index 000000000000..05db12e49a13
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchedSparseSetArray.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2022 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.utils;
+
+import android.annotation.NonNull;
+import android.util.ArraySet;
+import android.util.SparseSetArray;
+
+
+/**
+ * A watched variant of SparseSetArray. Changes to the array are notified to
+ * registered {@link Watcher}s.
+ * @param <T> The element type, stored in the SparseSetArray.
+ */
+public class WatchedSparseSetArray<T> extends WatchableImpl implements Snappable {
+ // The storage
+ private final SparseSetArray mStorage;
+
+ // A private convenience function
+ private void onChanged() {
+ dispatchChange(this);
+ }
+
+ public WatchedSparseSetArray() {
+ mStorage = new SparseSetArray();
+ }
+
+ /**
+ * Creates a new WatchedSparseSetArray from an existing WatchedSparseSetArray and copy its data
+ */
+ public WatchedSparseSetArray(@NonNull WatchedSparseSetArray<T> watchedSparseSetArray) {
+ mStorage = new SparseSetArray(watchedSparseSetArray.untrackedStorage());
+ }
+
+ /**
+ * Return the underlying storage. This breaks the wrapper but is necessary when
+ * passing the array to distant methods.
+ */
+ public SparseSetArray<T> untrackedStorage() {
+ return mStorage;
+ }
+
+ /**
+ * Add a value for key n.
+ * @return FALSE when the value already existed for the given key, TRUE otherwise.
+ */
+ public boolean add(int n, T value) {
+ final boolean res = mStorage.add(n, value);
+ onChanged();
+ return res;
+ }
+
+ /**
+ * Removes all mappings from this SparseSetArray.
+ */
+ public void clear() {
+ mStorage.clear();
+ onChanged();
+ }
+
+ /**
+ * @return whether the value exists for the key n.
+ */
+ public boolean contains(int n, T value) {
+ return mStorage.contains(n, value);
+ }
+
+ /**
+ * @return the set of items of key n
+ */
+ public ArraySet<T> get(int n) {
+ return mStorage.get(n);
+ }
+
+ /**
+ * Remove a value for key n.
+ * @return TRUE when the value existed for the given key and removed, FALSE otherwise.
+ */
+ public boolean remove(int n, T value) {
+ if (mStorage.remove(n, value)) {
+ onChanged();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Remove all values for key n.
+ */
+ public void remove(int n) {
+ mStorage.remove(n);
+ onChanged();
+ }
+
+ /**
+ * Return the size of the SparseSetArray.
+ */
+ public int size() {
+ return mStorage.size();
+ }
+
+ /**
+ * Return the key stored at the given index.
+ */
+ public int keyAt(int index) {
+ return mStorage.keyAt(index);
+ }
+
+ /**
+ * Return the size of the array at the given index.
+ */
+ public int sizeAt(int index) {
+ return mStorage.sizeAt(index);
+ }
+
+ /**
+ * Return the value in the SetArray at the given key index and value index.
+ */
+ public T valueAt(int intIndex, int valueIndex) {
+ return (T) mStorage.valueAt(intIndex, valueIndex);
+ }
+
+ @NonNull
+ @Override
+ public Object snapshot() {
+ WatchedSparseSetArray l = new WatchedSparseSetArray(this);
+ l.seal();
+ return l;
+ }
+
+ /**
+ * Make <this> a snapshot of the argument. Note that <this> is immutable when the
+ * method returns. <this> must be empty when the function is called.
+ * @param r The source array, which is copied into <this>
+ */
+ public void snapshot(@NonNull WatchedSparseSetArray<T> r) {
+ snapshot(this, r);
+ }
+
+ /**
+ * Make the destination a copy of the source. If the element is a subclass of Snapper then the
+ * copy contains snapshots of the elements. Otherwise the copy contains references to the
+ * elements. The destination must be initially empty. Upon return, the destination is
+ * immutable.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array. It is not modified.
+ */
+ public static void snapshot(@NonNull WatchedSparseSetArray dst,
+ @NonNull WatchedSparseSetArray src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int arraySize = src.size();
+ for (int i = 0; i < arraySize; i++) {
+ final ArraySet set = src.get(i);
+ final int setSize = set.size();
+ for (int j = 0; j < setSize; j++) {
+ dst.add(src.keyAt(i), set.valueAt(j));
+ }
+ }
+ dst.seal();
+ }
+}
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index 092853f298c2..89470ec00a6c 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -145,7 +145,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
filter.addAction(ACTION_MULTI_SIM_CONFIG_CHANGED);
- mContext.registerReceiver(this, filter, null, mHandler, Context.RECEIVER_NOT_EXPORTED);
+ mContext.registerReceiver(this, filter, null, mHandler);
mSubscriptionManager.addOnSubscriptionsChangedListener(
executor, mSubscriptionChangedListener);
mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener);
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index e9535e0a56e1..bedb9f0528c6 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -700,5 +700,9 @@ final class VibrationSettings {
@Override
public void onUidCachedChanged(int uid, boolean cached) {
}
+
+ @Override
+ public void onUidProcAdjChanged(int uid) {
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 8018d5652b1b..5fdcd690b5e2 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -85,6 +85,7 @@ import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.LocalServices;
import com.android.server.Watchdog;
+import com.android.server.pm.KnownPackages;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.uri.NeededUriGrants;
import com.android.server.vr.VrManagerInternal;
@@ -627,7 +628,7 @@ class ActivityClientController extends IActivityClientController.Stub {
return true;
}
final String[] installerNames = pm.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.getUserId(uid));
+ KnownPackages.PACKAGE_INSTALLER, UserHandle.getUserId(uid));
return installerNames.length > 0 && callingPkg.getPackageName().equals(installerNames[0]);
}
diff --git a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
index 1d65cbb70ffe..d2053fa25ad8 100644
--- a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
+++ b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
@@ -108,11 +108,13 @@ public abstract class ActivityInterceptorCallback {
public final int callingPid;
public final int callingUid;
public final ActivityOptions checkedOptions;
+ public final @Nullable Runnable clearOptionsAnimation;
public ActivityInterceptorInfo(int realCallingUid, int realCallingPid, int userId,
String callingPackage, String callingFeatureId, Intent intent,
ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, int callingPid,
- int callingUid, ActivityOptions checkedOptions) {
+ int callingUid, ActivityOptions checkedOptions,
+ @Nullable Runnable clearOptionsAnimation) {
this.realCallingUid = realCallingUid;
this.realCallingPid = realCallingPid;
this.userId = userId;
@@ -125,6 +127,7 @@ public abstract class ActivityInterceptorCallback {
this.callingPid = callingPid;
this.callingUid = callingUid;
this.checkedOptions = checkedOptions;
+ this.clearOptionsAnimation = clearOptionsAnimation;
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 0b52fd643a1c..d8ad2a57afa4 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4592,14 +4592,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
applyOptionsAnimation(mPendingOptions, intent);
}
- if (task == null) {
- clearOptionsAnimation();
- } else {
- // This will clear the options for all the ActivityRecords for this Task.
- task.forAllActivities((r) -> {
- r.clearOptionsAnimation();
- });
- }
+ clearOptionsAnimationForSiblings();
}
/**
@@ -4786,6 +4779,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mPendingRemoteTransition = null;
}
+ void clearOptionsAnimationForSiblings() {
+ if (task == null) {
+ clearOptionsAnimation();
+ } else {
+ // This will clear the options for all the ActivityRecords for this Task.
+ task.forAllActivities(ActivityRecord::clearOptionsAnimation);
+ }
+ }
+
ActivityOptions getOptions() {
return mPendingOptions;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index cdeb86c3ee77..a452013bf42a 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -188,7 +188,7 @@ class ActivityStartInterceptor {
final SparseArray<ActivityInterceptorCallback> callbacks =
mService.getActivityInterceptorCallbacks();
final ActivityInterceptorCallback.ActivityInterceptorInfo interceptorInfo =
- getInterceptorInfo();
+ getInterceptorInfo(null /* clearOptionsAnimation */);
for (int i = 0; i < callbacks.size(); i++) {
final ActivityInterceptorCallback callback = callbacks.valueAt(i);
@@ -406,20 +406,22 @@ class ActivityStartInterceptor {
/**
* Called when an activity is successfully launched.
*/
- void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo) {
+ void onActivityLaunched(TaskInfo taskInfo, ActivityRecord r) {
final SparseArray<ActivityInterceptorCallback> callbacks =
mService.getActivityInterceptorCallbacks();
- ActivityInterceptorCallback.ActivityInterceptorInfo info = getInterceptorInfo();
+ ActivityInterceptorCallback.ActivityInterceptorInfo info = getInterceptorInfo(
+ r::clearOptionsAnimationForSiblings);
for (int i = 0; i < callbacks.size(); i++) {
final ActivityInterceptorCallback callback = callbacks.valueAt(i);
- callback.onActivityLaunched(taskInfo, activityInfo, info);
+ callback.onActivityLaunched(taskInfo, r.info, info);
}
}
- private ActivityInterceptorCallback.ActivityInterceptorInfo getInterceptorInfo() {
+ private ActivityInterceptorCallback.ActivityInterceptorInfo getInterceptorInfo(
+ @Nullable Runnable clearOptionsAnimation) {
return new ActivityInterceptorCallback.ActivityInterceptorInfo(mRealCallingUid,
mRealCallingPid, mUserId, mCallingPackage, mCallingFeatureId, mIntent,
mRInfo, mAInfo, mResolvedType, mCallingPid, mCallingUid,
- mActivityOptions);
+ mActivityOptions, clearOptionsAnimation);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 0b717540a7a6..003268b33cdc 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1585,7 +1585,7 @@ class ActivityStarter {
}
if (ActivityManager.isStartResultSuccessful(result)) {
- mInterceptor.onActivityLaunched(targetTask.getTaskInfo(), r.info);
+ mInterceptor.onActivityLaunched(targetTask.getTaskInfo(), r);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 9267f2f6f921..14436bc4ed66 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3599,25 +3599,41 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mAmInternal.enforceCallingPermission(READ_FRAME_BUFFER, "getTaskSnapshot()");
final long ident = Binder.clearCallingIdentity();
try {
- return getTaskSnapshot(taskId, isLowResolution, true /* restoreFromDisk */);
+ final Task task;
+ synchronized (mGlobalLock) {
+ task = mRootWindowContainer.anyTaskForId(taskId,
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
+ if (task == null) {
+ Slog.w(TAG, "getTaskSnapshot: taskId=" + taskId + " not found");
+ return null;
+ }
+ }
+ // Don't call this while holding the lock as this operation might hit the disk.
+ return mWindowManager.mTaskSnapshotController.getSnapshot(taskId, task.mUserId,
+ true /* restoreFromDisk */, isLowResolution);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
- private TaskSnapshot getTaskSnapshot(int taskId, boolean isLowResolution,
- boolean restoreFromDisk) {
- final Task task;
- synchronized (mGlobalLock) {
- task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
- if (task == null) {
- Slog.w(TAG, "getTaskSnapshot: taskId=" + taskId + " not found");
- return null;
+ @Override
+ public TaskSnapshot takeTaskSnapshot(int taskId) {
+ mAmInternal.enforceCallingPermission(READ_FRAME_BUFFER, "takeTaskSnapshot()");
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final Task task = mRootWindowContainer.anyTaskForId(taskId,
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
+ if (task == null || !task.isVisible()) {
+ Slog.w(TAG, "takeTaskSnapshot: taskId=" + taskId + " not found or not visible");
+ return null;
+ }
+ return mWindowManager.mTaskSnapshotController.captureTaskSnapshot(
+ task, false /* snapshotHome */);
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- // Don't call this while holding the lock as this operation might hit the disk.
- return task.getSnapshot(isLowResolution, restoreFromDisk);
}
/** Return the user id of the last resumed activity. */
@@ -6559,8 +6575,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public TaskSnapshot getTaskSnapshotBlocking(
int taskId, boolean isLowResolution) {
- return ActivityTaskManagerService.this.getTaskSnapshot(taskId, isLowResolution,
- true /* restoreFromDisk */);
+ return ActivityTaskManagerService.this.getTaskSnapshot(taskId, isLowResolution);
}
@Override
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 8eb0046ff923..a982078a25b6 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -53,6 +53,7 @@ import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.view.View.GONE;
+import static android.view.ViewRootImpl.LOCAL_LAYOUT;
import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.systemBars;
@@ -354,6 +355,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
int mInitialDisplayWidth = 0;
int mInitialDisplayHeight = 0;
int mInitialDisplayDensity = 0;
+ float mInitialPhysicalXDpi = 0.0f;
+ float mInitialPhysicalYDpi = 0.0f;
DisplayCutout mInitialDisplayCutout;
private final RotationCache<DisplayCutout, WmDisplayCutout> mDisplayCutoutCache
@@ -394,6 +397,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
boolean mIsDensityForced = false;
/**
+ * Overridden display physical dpi.
+ */
+ float mBaseDisplayPhysicalXDpi = 0.0f;
+ float mBaseDisplayPhysicalYDpi = 0.0f;
+
+ /**
* Whether to disable display scaling. This can be set via shell command "adb shell wm scaling".
* @see WindowManagerService#setForcedDisplayScalingMode(int, int)
*/
@@ -426,7 +435,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
/**
* Compat metrics computed based on {@link #mDisplayMetrics}.
- * @see #updateDisplayAndOrientation(int)
+ * @see #updateDisplayAndOrientation(int, Configuration)
*/
private final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics();
@@ -2034,6 +2043,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mDisplayInfo.logicalWidth = dw;
mDisplayInfo.logicalHeight = dh;
mDisplayInfo.logicalDensityDpi = mBaseDisplayDensity;
+ mDisplayInfo.physicalXDpi = mBaseDisplayPhysicalXDpi;
+ mDisplayInfo.physicalYDpi = mBaseDisplayPhysicalYDpi;
mDisplayInfo.appWidth = appWidth;
mDisplayInfo.appHeight = appHeight;
if (isDefaultDisplay) {
@@ -2647,29 +2658,27 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mCurrentPrivacyIndicatorBounds =
mCurrentPrivacyIndicatorBounds.updateStaticBounds(staticBounds);
if (!Objects.equals(oldBounds, mCurrentPrivacyIndicatorBounds)) {
- final DisplayInfo info = mDisplayInfo;
- if (mDisplayFrames.onDisplayInfoUpdated(info,
- calculateDisplayCutoutForRotation(info.rotation),
- calculateRoundedCornersForRotation(info.rotation),
- calculatePrivacyIndicatorBoundsForRotation(info.rotation))) {
- mInsetsStateController.onDisplayInfoUpdated(true);
- }
+ updateDisplayFrames(false /* insetsSourceMayChange */, true /* notifyInsetsChange */);
}
}
void onDisplayInfoChanged() {
- final DisplayInfo info = mDisplayInfo;
- if (mDisplayFrames.onDisplayInfoUpdated(info,
- calculateDisplayCutoutForRotation(info.rotation),
- calculateRoundedCornersForRotation(info.rotation),
- calculatePrivacyIndicatorBoundsForRotation(info.rotation))) {
- // TODO(b/161810301): Set notifyInsetsChange to true while the server no longer performs
- // layout.
- mInsetsStateController.onDisplayInfoUpdated(false /* notifyInsetsChanged */);
- }
+ updateDisplayFrames(LOCAL_LAYOUT, LOCAL_LAYOUT);
mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp();
- mInputMonitor.layoutInputConsumers(info.logicalWidth, info.logicalHeight);
- mDisplayPolicy.onDisplayInfoChanged(info);
+ mInputMonitor.layoutInputConsumers(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
+ mDisplayPolicy.onDisplayInfoChanged(mDisplayInfo);
+ }
+
+ private void updateDisplayFrames(boolean insetsSourceMayChange, boolean notifyInsetsChange) {
+ if (mDisplayFrames.update(mDisplayInfo,
+ calculateDisplayCutoutForRotation(mDisplayInfo.rotation),
+ calculateRoundedCornersForRotation(mDisplayInfo.rotation),
+ calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation))) {
+ if (insetsSourceMayChange) {
+ mDisplayPolicy.updateInsetsSourceFramesExceptIme(mDisplayFrames);
+ }
+ mInsetsStateController.onDisplayFramesUpdated(notifyInsetsChange);
+ }
}
@Override
@@ -2698,10 +2707,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
updateBaseDisplayMetrics(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight,
- mDisplayInfo.logicalDensityDpi);
+ mDisplayInfo.logicalDensityDpi, mDisplayInfo.physicalXDpi,
+ mDisplayInfo.physicalYDpi);
mInitialDisplayWidth = mDisplayInfo.logicalWidth;
mInitialDisplayHeight = mDisplayInfo.logicalHeight;
mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
+ mInitialPhysicalXDpi = mDisplayInfo.physicalXDpi;
+ mInitialPhysicalYDpi = mDisplayInfo.physicalYDpi;
mInitialDisplayCutout = mDisplayInfo.displayCutout;
mInitialRoundedCorners = mDisplayInfo.roundedCorners;
mCurrentPrivacyIndicatorBounds = new PrivacyIndicatorBounds(new Rect[4],
@@ -2720,6 +2732,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final int newWidth = rotated ? mDisplayInfo.logicalHeight : mDisplayInfo.logicalWidth;
final int newHeight = rotated ? mDisplayInfo.logicalWidth : mDisplayInfo.logicalHeight;
final int newDensity = mDisplayInfo.logicalDensityDpi;
+ final float newXDpi = mDisplayInfo.physicalXDpi;
+ final float newYDpi = mDisplayInfo.physicalYDpi;
final DisplayCutout newCutout = mIgnoreDisplayCutout
? DisplayCutout.NO_CUTOUT : mDisplayInfo.displayCutout;
final String newUniqueId = mDisplayInfo.uniqueId;
@@ -2727,7 +2741,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final boolean displayMetricsChanged = mInitialDisplayWidth != newWidth
|| mInitialDisplayHeight != newHeight
- || mInitialDisplayDensity != mDisplayInfo.logicalDensityDpi
+ || mInitialDisplayDensity != newDensity
+ || mInitialPhysicalXDpi != newXDpi
+ || mInitialPhysicalYDpi != newYDpi
|| !Objects.equals(mInitialDisplayCutout, newCutout)
|| !Objects.equals(mInitialRoundedCorners, newRoundedCorners);
final boolean physicalDisplayChanged = !newUniqueId.equals(mCurrentUniqueDisplayId);
@@ -2744,7 +2760,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// If there is an override set for base values - use it, otherwise use new values.
updateBaseDisplayMetrics(mIsSizeForced ? mBaseDisplayWidth : newWidth,
mIsSizeForced ? mBaseDisplayHeight : newHeight,
- mIsDensityForced ? mBaseDisplayDensity : newDensity);
+ mIsDensityForced ? mBaseDisplayDensity : newDensity,
+ mIsSizeForced ? mBaseDisplayPhysicalXDpi : newXDpi,
+ mIsSizeForced ? mBaseDisplayPhysicalYDpi : newYDpi);
configureDisplayPolicy();
@@ -2759,6 +2777,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mInitialDisplayWidth = newWidth;
mInitialDisplayHeight = newHeight;
mInitialDisplayDensity = newDensity;
+ mInitialPhysicalXDpi = newXDpi;
+ mInitialPhysicalYDpi = newYDpi;
mInitialDisplayCutout = newCutout;
mInitialRoundedCorners = newRoundedCorners;
mCurrentUniqueDisplayId = newUniqueId;
@@ -2775,19 +2795,25 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mMaxUiWidth = width;
// Update existing metrics.
- updateBaseDisplayMetrics(mBaseDisplayWidth, mBaseDisplayHeight, mBaseDisplayDensity);
+ updateBaseDisplayMetrics(mBaseDisplayWidth, mBaseDisplayHeight, mBaseDisplayDensity,
+ mBaseDisplayPhysicalXDpi, mBaseDisplayPhysicalYDpi);
}
/** Update base (override) display metrics. */
- void updateBaseDisplayMetrics(int baseWidth, int baseHeight, int baseDensity) {
+ void updateBaseDisplayMetrics(int baseWidth, int baseHeight, int baseDensity, float baseXDpi,
+ float baseYDpi) {
mBaseDisplayWidth = baseWidth;
mBaseDisplayHeight = baseHeight;
mBaseDisplayDensity = baseDensity;
+ mBaseDisplayPhysicalXDpi = baseXDpi;
+ mBaseDisplayPhysicalYDpi = baseYDpi;
if (mMaxUiWidth > 0 && mBaseDisplayWidth > mMaxUiWidth) {
final float ratio = mMaxUiWidth / (float) mBaseDisplayWidth;
mBaseDisplayHeight = (int) (mBaseDisplayHeight * ratio);
mBaseDisplayWidth = mMaxUiWidth;
+ mBaseDisplayPhysicalXDpi = mBaseDisplayPhysicalXDpi * ratio;
+ mBaseDisplayPhysicalYDpi = mBaseDisplayPhysicalYDpi * ratio;
if (!mIsDensityForced) {
// Update the density proportionally so the size of the UI elements won't change
// from the user's perspective.
@@ -2861,7 +2887,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
Slog.i(TAG_WM, "Using new display size: " + width + "x" + height);
- updateBaseDisplayMetrics(width, height, mBaseDisplayDensity);
+ updateBaseDisplayMetrics(width, height, mBaseDisplayDensity, mBaseDisplayPhysicalXDpi,
+ mBaseDisplayPhysicalYDpi);
reconfigureDisplayLocked();
if (!mIsSizeForced) {
@@ -3979,6 +4006,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
ProtoLog.i(WM_DEBUG_IME, "setInputMethodTarget %s", target);
+ final boolean layeringTargetChanged = target != mImeLayeringTarget;
mImeLayeringTarget = target;
// 1. Reparent the IME container window to the target root DA to get the correct bounds and
@@ -4006,7 +4034,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// 4. Update the IME control target to apply any inset change and animation.
// 5. Reparent the IME container surface to either the input target app, or the IME window
// parent.
- updateImeControlTarget(true /* forceUpdateImeParent */);
+ updateImeControlTarget(layeringTargetChanged);
}
@VisibleForTesting
@@ -4140,6 +4168,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final SurfaceControl.Transaction t = getPendingTransaction();
// Prepare IME screenshot for the target if it allows to attach into.
if (mInputMethodWindow != null && mInputMethodWindow.isVisible()) {
+ // Remove the obsoleted IME snapshot first in case the new snapshot happens to
+ // override the current one before the transition finish and the surface never be
+ // removed on the task.
+ removeImeSurfaceImmediately();
mImeScreenshot = new ImeScreenshot(
mWmService.mSurfaceControlFactory.apply(null), mImeLayeringTarget);
mImeScreenshot.attachAndShow(t);
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index 45d7141fd556..76aa7f963aa6 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -64,26 +64,26 @@ public class DisplayFrames {
PrivacyIndicatorBounds indicatorBounds) {
mDisplayId = displayId;
mInsetsState = insetsState;
- onDisplayInfoUpdated(info, displayCutout, roundedCorners, indicatorBounds);
+ update(info, displayCutout, roundedCorners, indicatorBounds);
}
/**
- * Update {@link DisplayFrames} when {@link DisplayInfo} is updated.
+ * This is called when {@link DisplayInfo} or {@link PrivacyIndicatorBounds} is updated.
*
* @param info the updated {@link DisplayInfo}.
* @param displayCutout the updated {@link DisplayCutout}.
* @param roundedCorners the updated {@link RoundedCorners}.
- * @return {@code true} if the insets state has been changed; {@code false} otherwise.
+ * @param indicatorBounds the updated {@link PrivacyIndicatorBounds}.
+ * @return {@code true} if anything has been changed; {@code false} otherwise.
*/
- public boolean onDisplayInfoUpdated(DisplayInfo info, @NonNull WmDisplayCutout displayCutout,
+ public boolean update(DisplayInfo info, @NonNull WmDisplayCutout displayCutout,
@NonNull RoundedCorners roundedCorners,
@NonNull PrivacyIndicatorBounds indicatorBounds) {
- mRotation = info.rotation;
-
final InsetsState state = mInsetsState;
final Rect safe = mDisplayCutoutSafe;
final DisplayCutout cutout = displayCutout.getDisplayCutout();
if (mDisplayWidth == info.logicalWidth && mDisplayHeight == info.logicalHeight
+ && mRotation != info.rotation
&& state.getDisplayCutout().equals(cutout)
&& state.getRoundedCorners().equals(roundedCorners)
&& state.getPrivacyIndicatorBounds().equals(indicatorBounds)) {
@@ -91,6 +91,7 @@ public class DisplayFrames {
}
mDisplayWidth = info.logicalWidth;
mDisplayHeight = info.logicalHeight;
+ mRotation = info.rotation;
final Rect unrestricted = mUnrestricted;
unrestricted.set(0, 0, mDisplayWidth, mDisplayHeight);
state.setDisplayFrame(unrestricted);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 4573ede13f7f..06f449e52478 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1498,10 +1498,6 @@ public class DisplayPolicy {
}
}
- // TODO(b/161810301): No one is calling this since we haven't moved window layout to the client.
- // When that happens, this should be called when the display rotation is
- // changed, so that we can dispatch the correct insets to all the clients
- // before the insets source windows report their frames to the server.
void updateInsetsSourceFramesExceptIme(DisplayFrames displayFrames) {
for (int i = mInsetsSourceWindowsExceptIme.size() - 1; i >= 0; i--) {
final WindowState win = mInsetsSourceWindowsExceptIme.valueAt(i);
@@ -1814,10 +1810,14 @@ public class DisplayPolicy {
/**
* Called when the resource overlays change.
*/
- public void onOverlayChangedLw() {
+ void onOverlayChanged() {
updateCurrentUserResources();
+ // Update the latest display size, cutout.
+ mDisplayContent.updateDisplayInfo();
+ // The height of status bar needs to update in case display cutout is changed.
onConfigurationChanged();
- mSystemGestures.onConfigurationChanged();
+ // The height of status bar can affect screen size configuration.
+ mDisplayContent.reconfigureDisplayLocked();
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 70c769d60844..11bcd8ca3681 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -277,7 +277,8 @@ class DisplayWindowSettings {
final int height = hasSizeOverride ? settings.mForcedHeight : dc.mInitialDisplayHeight;
final int density = hasDensityOverride ? settings.mForcedDensity
: dc.mInitialDisplayDensity;
- dc.updateBaseDisplayMetrics(width, height, density);
+ dc.updateBaseDisplayMetrics(width, height, density, dc.mBaseDisplayPhysicalXDpi,
+ dc.mBaseDisplayPhysicalYDpi);
final int forcedScalingMode = settings.mForcedScalingMode != null
? settings.mForcedScalingMode : FORCE_SCALING_MODE_AUTO;
diff --git a/services/core/java/com/android/server/wm/FactoryErrorDialog.java b/services/core/java/com/android/server/wm/FactoryErrorDialog.java
index afdf1ee4de7f..4ebaad98cd75 100644
--- a/services/core/java/com/android/server/wm/FactoryErrorDialog.java
+++ b/services/core/java/com/android/server/wm/FactoryErrorDialog.java
@@ -37,9 +37,6 @@ final class FactoryErrorDialog extends BaseErrorDialog {
attrs.setTitle("Factory Error");
getWindow().setAttributes(attrs);
}
-
- public void onStop() {
- }
@Override
protected void closeDialog() {
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 8038f4404799..00f7e6362be9 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -414,10 +414,9 @@ final class InputMonitor {
final IBinder focusToken = focus != null ? focus.mInputChannelToken : null;
if (focusToken == null) {
- mInputFocus = null;
// When an app is focused, but its window is not showing yet, remove the input focus
// from the current window.
- if (mDisplayContent.mFocusedApp != null) {
+ if (mDisplayContent.mFocusedApp != null && mInputFocus != null) {
ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "App %s is focused,"
+ " but the window is not ready. Start a transaction to remove focus from"
+ " the window of non-focused apps.",
@@ -426,6 +425,7 @@ final class InputMonitor {
"reason=UpdateInputWindows");
mInputTransaction.removeCurrentInputFocus(mDisplayId);
}
+ mInputFocus = null;
return;
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index a19d72e37124..ed771c202c04 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -177,7 +177,7 @@ class InsetsStateController {
}
}
- void onDisplayInfoUpdated(boolean notifyInsetsChange) {
+ void onDisplayFramesUpdated(boolean notifyInsetsChange) {
final ArrayList<WindowState> insetsChangedWindows = new ArrayList<>();
mDisplayContent.forAllWindows(w -> {
w.mAboveInsetsState.set(mState, displayCutout());
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index b57670914c11..65dca86d0259 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -50,7 +50,6 @@ import com.android.server.AnimationThread;
import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
import java.util.ArrayList;
-import java.util.List;
import java.util.function.Supplier;
/**
@@ -66,6 +65,12 @@ class SurfaceAnimationRunner {
*/
private final Object mCancelLock = new Object();
+ /**
+ * Lock for synchronizing {@link #mEdgeExtensions} to prevent race conditions when managing
+ * created edge extension surfaces.
+ */
+ private final Object mEdgeExtensionLock = new Object();
+
@VisibleForTesting
Choreographer mChoreographer;
@@ -93,6 +98,11 @@ class SurfaceAnimationRunner {
@GuardedBy("mLock")
private boolean mAnimationStartDeferred;
+ // Mapping animation leashes to a list of edge extension surfaces associated with them
+ @GuardedBy("mEdgeExtensionLock")
+ private final ArrayMap<SurfaceControl, ArrayList<SurfaceControl>> mEdgeExtensions =
+ new ArrayMap<>();
+
/**
* There should only ever be one instance of this class. Usual spot for it is with
* {@link WindowManagerService}
@@ -154,21 +164,22 @@ class SurfaceAnimationRunner {
boolean requiresEdgeExtension = requiresEdgeExtension(a);
if (requiresEdgeExtension) {
+ final ArrayList<SurfaceControl> extensionSurfaces = new ArrayList<>();
+ synchronized (mEdgeExtensionLock) {
+ mEdgeExtensions.put(animationLeash, extensionSurfaces);
+ }
+
mPreProcessingAnimations.put(animationLeash, runningAnim);
// We must wait for t to be committed since otherwise the leash doesn't have the
// windows we want to screenshot and extend as children.
t.addTransactionCommittedListener(Runnable::run, () -> {
final WindowAnimationSpec animationSpec = a.asWindowAnimationSpec();
- final Runnable cleanUpEdgeExtension = edgeExtendWindow(animationLeash,
+
+ edgeExtendWindow(animationLeash,
animationSpec.getRootTaskBounds(), animationSpec.getAnimation(),
mFrameTransaction);
- runningAnim.mFinishCallback = () -> {
- cleanUpEdgeExtension.run();
- finishCallback.run();
- };
-
synchronized (mLock) {
// only run if animation is not yet canceled by this point
if (mPreProcessingAnimations.get(animationLeash) == runningAnim) {
@@ -320,7 +331,7 @@ class SurfaceAnimationRunner {
mApplyScheduled = false;
}
- private Runnable edgeExtendWindow(SurfaceControl leash, Rect bounds, Animation a,
+ private void edgeExtendWindow(SurfaceControl leash, Rect bounds, Animation a,
Transaction transaction) {
final Transformation transformationAtStart = new Transformation();
a.getTransformationAt(0, transformationAtStart);
@@ -335,17 +346,14 @@ class SurfaceAnimationRunner {
final int targetSurfaceHeight = bounds.height();
final int targetSurfaceWidth = bounds.width();
- final List<SurfaceControl> extensionSurfaces = new ArrayList<>();
-
if (maxExtensionInsets.left < 0) {
final Rect edgeBounds = new Rect(0, 0, 1, targetSurfaceHeight);
final Rect extensionRect = new Rect(0, 0,
-maxExtensionInsets.left, targetSurfaceHeight);
final int xPos = maxExtensionInsets.left;
final int yPos = 0;
- final SurfaceControl extensionSurface = createExtensionSurface(leash, edgeBounds,
+ createExtensionSurface(leash, edgeBounds,
extensionRect, xPos, yPos, "Left Edge Extension", transaction);
- extensionSurfaces.add(extensionSurface);
}
if (maxExtensionInsets.top < 0) {
@@ -354,9 +362,8 @@ class SurfaceAnimationRunner {
targetSurfaceWidth, -maxExtensionInsets.top);
final int xPos = 0;
final int yPos = maxExtensionInsets.top;
- final SurfaceControl extensionSurface = createExtensionSurface(leash, edgeBounds,
+ createExtensionSurface(leash, edgeBounds,
extensionRect, xPos, yPos, "Top Edge Extension", transaction);
- extensionSurfaces.add(extensionSurface);
}
if (maxExtensionInsets.right < 0) {
@@ -366,9 +373,8 @@ class SurfaceAnimationRunner {
-maxExtensionInsets.right, targetSurfaceHeight);
final int xPos = targetSurfaceWidth;
final int yPos = 0;
- final SurfaceControl extensionSurface = createExtensionSurface(leash, edgeBounds,
+ createExtensionSurface(leash, edgeBounds,
extensionRect, xPos, yPos, "Right Edge Extension", transaction);
- extensionSurfaces.add(extensionSurface);
}
if (maxExtensionInsets.bottom < 0) {
@@ -378,23 +384,25 @@ class SurfaceAnimationRunner {
targetSurfaceWidth, -maxExtensionInsets.bottom);
final int xPos = maxExtensionInsets.left;
final int yPos = targetSurfaceHeight;
- final SurfaceControl extensionSurface = createExtensionSurface(leash, edgeBounds,
+ createExtensionSurface(leash, edgeBounds,
extensionRect, xPos, yPos, "Bottom Edge Extension", transaction);
- extensionSurfaces.add(extensionSurface);
}
+ }
- Runnable cleanUp = () -> {
- for (final SurfaceControl extensionSurface : extensionSurfaces) {
- if (extensionSurface != null) {
- transaction.remove(extensionSurface);
- }
+ private void createExtensionSurface(SurfaceControl leash, Rect edgeBounds,
+ Rect extensionRect, int xPos, int yPos, String layerName,
+ Transaction startTransaction) {
+ synchronized (mEdgeExtensionLock) {
+ if (!mEdgeExtensions.containsKey(leash)) {
+ // Animation leash has already been removed so we shouldn't perform any extension
+ return;
}
- };
-
- return cleanUp;
+ createExtensionSurfaceLocked(leash, edgeBounds, extensionRect, xPos, yPos, layerName,
+ startTransaction);
+ }
}
- private SurfaceControl createExtensionSurface(SurfaceControl surfaceToExtend, Rect edgeBounds,
+ private void createExtensionSurfaceLocked(SurfaceControl surfaceToExtend, Rect edgeBounds,
Rect extensionRect, int xPos, int yPos, String layerName,
Transaction startTransaction) {
final SurfaceControl edgeExtensionLayer = new SurfaceControl.Builder()
@@ -420,7 +428,7 @@ class SurfaceAnimationRunner {
if (edgeBuffer == null) {
Log.e("SurfaceAnimationRunner", "Failed to create edge extension - "
+ "edge buffer is null");
- return null;
+ return;
}
android.graphics.BitmapShader shader =
@@ -440,13 +448,13 @@ class SurfaceAnimationRunner {
startTransaction.setPosition(edgeExtensionLayer, xPos, yPos);
startTransaction.setVisibility(edgeExtensionLayer, true);
- return edgeExtensionLayer;
+ mEdgeExtensions.get(surfaceToExtend).add(edgeExtensionLayer);
}
private static final class RunningAnimation {
final AnimationSpec mAnimSpec;
final SurfaceControl mLeash;
- Runnable mFinishCallback;
+ final Runnable mFinishCallback;
ValueAnimator mAnim;
@GuardedBy("mCancelLock")
@@ -459,6 +467,22 @@ class SurfaceAnimationRunner {
}
}
+ protected void onAnimationLeashLost(SurfaceControl animationLeash,
+ Transaction t) {
+ synchronized (mEdgeExtensionLock) {
+ if (!mEdgeExtensions.containsKey(animationLeash)) {
+ return;
+ }
+
+ final ArrayList<SurfaceControl> edgeExtensions = mEdgeExtensions.get(animationLeash);
+ for (int i = 0; i < edgeExtensions.size(); i++) {
+ final SurfaceControl extension = edgeExtensions.get(i);
+ t.remove(extension);
+ }
+ mEdgeExtensions.remove(animationLeash);
+ }
+ }
+
@VisibleForTesting
interface AnimatorFactory {
ValueAnimator makeAnimator();
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 731a04500b57..6ab3916425f9 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -26,7 +26,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -968,17 +967,6 @@ class Task extends TaskFragment {
|| targetWindowingMode == WINDOWING_MODE_FREEFORM;
}
- /**
- * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD!
- */
- TaskSnapshot getSnapshot(boolean isLowResolution, boolean restoreFromDisk) {
-
- // TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more
- // synchronized between AM and WM.
- return mAtmService.mWindowManager.getTaskSnapshot(mTaskId, mUserId, isLowResolution,
- restoreFromDisk);
- }
-
void touchActiveTime() {
lastActiveTime = SystemClock.elapsedRealtime();
}
@@ -2701,7 +2689,7 @@ class Task extends TaskFragment {
@Override
void onDisplayChanged(DisplayContent dc) {
final boolean isRootTask = isRootTask();
- if (!isRootTask) {
+ if (!isRootTask && !mCreatedByOrganizer) {
adjustBoundsForDisplayChangeIfNeeded(dc);
}
super.onDisplayChanged(dc);
@@ -3468,9 +3456,9 @@ class Task extends TaskFragment {
forAllActivities(r -> {
info.addLaunchCookie(r.mLaunchCookie);
});
- final Task rootTask = getRootTask();
- info.parentTaskId = rootTask == getParent() && rootTask.mCreatedByOrganizer
- ? rootTask.mTaskId
+ final Task parentTask = getParent() != null ? getParent().asTask() : null;
+ info.parentTaskId = parentTask != null && parentTask.mCreatedByOrganizer
+ ? parentTask.mTaskId
: INVALID_TASK_ID;
info.isFocused = isFocused();
info.isVisible = hasVisibleChildren();
@@ -4146,13 +4134,13 @@ class Task extends TaskFragment {
private boolean canBeOrganized() {
// All root tasks can be organized
- if (isRootTask()) {
+ if (isRootTask() || mCreatedByOrganizer) {
return true;
}
- // Task could be organized if it's the direct child of the root created by organizer.
- final Task rootTask = getRootTask();
- return rootTask == getParent() && rootTask.mCreatedByOrganizer;
+ // Task could be organized if it's the direct child of a task created by organizer.
+ final Task parentTask = getParent().asTask();
+ return parentTask != null && parentTask.mCreatedByOrganizer;
}
@Override
@@ -4341,9 +4329,7 @@ class Task extends TaskFragment {
int elevation = 0;
// Get elevation for a specific windowing mode.
- if (inPinnedWindowingMode()) {
- elevation = PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
- } else if (inFreeformWindowingMode()) {
+ if (inFreeformWindowingMode()) {
elevation = taskIsFocused
? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
} else {
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 23df429c3f24..3a458fdc75bb 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1825,8 +1825,6 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return false;
}
if (tda == null) {
- Slog.w(TAG, "Can't find TaskDisplayArea to determine support for multi"
- + " window. Task id=" + getTaskId() + " attached=" + isAttached());
return false;
}
if (!getTask().isResizeable() && !tda.supportsNonResizableMultiWindow()) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 973f98310d3e..c44f08cbd1eb 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1316,11 +1316,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
change.setMode(info.getTransitMode(target));
change.setStartAbsBounds(info.mAbsoluteBounds);
- change.setEndAbsBounds(target.getBounds());
- change.setEndRelOffset(target.getBounds().left - target.getParent().getBounds().left,
- target.getBounds().top - target.getParent().getBounds().top);
change.setFlags(info.getChangeFlags(target));
- change.setRotation(info.mRotation, target.getWindowConfiguration().getRotation());
final Task task = target.asTask();
if (task != null) {
final ActivityManager.RunningTaskInfo tinfo = new ActivityManager.RunningTaskInfo();
@@ -1348,13 +1344,32 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
} else if ((info.mFlags & ChangeInfo.FLAG_SEAMLESS_ROTATION) != 0) {
change.setRotationAnimation(ROTATION_ANIMATION_SEAMLESS);
}
+
+ final WindowContainer<?> parent = target.getParent();
+ final Rect bounds = target.getBounds();
+ final Rect parentBounds = parent.getBounds();
+ change.setEndRelOffset(bounds.left - parentBounds.left,
+ bounds.top - parentBounds.top);
+ int endRotation = target.getWindowConfiguration().getRotation();
final ActivityRecord activityRecord = target.asActivityRecord();
if (activityRecord != null) {
final Task arTask = activityRecord.getTask();
final int backgroundColor = ColorUtils.setAlphaComponent(
arTask.getTaskDescription().getBackgroundColor(), 255);
change.setBackgroundColor(backgroundColor);
+ // TODO(b/227427984): Shell needs to aware letterbox.
+ // Always use parent bounds of activity because letterbox area (e.g. fixed aspect
+ // ratio or size compat mode) should be included in the animation.
+ change.setEndAbsBounds(parentBounds);
+ if (activityRecord.getRelativeDisplayRotation() != 0
+ && !activityRecord.mTransitionController.useShellTransitionsRotation()) {
+ // Use parent rotation because shell doesn't know the surface is rotated.
+ endRotation = parent.getWindowConfiguration().getRotation();
+ }
+ } else {
+ change.setEndAbsBounds(bounds);
}
+ change.setRotation(info.mRotation, endRotation);
out.addChange(change);
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 23479a269de7..c1c390eea932 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -430,7 +430,7 @@ class TransitionController {
}, true /* traverseTopToBottom */);
// Collect all visible non-app windows which need to be drawn before the animation starts.
dc.forAllWindows(w -> {
- if (w.mActivityRecord == null && w.isVisible() && !inTransition(w.mToken)
+ if (w.mActivityRecord == null && w.isVisible() && !isCollecting(w.mToken)
&& dc.shouldSyncRotationChange(w)) {
transition.collect(w.mToken);
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 99e39f1969e1..214524c2f42c 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3179,6 +3179,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
@Override
public void onAnimationLeashLost(Transaction t) {
mLastLayer = -1;
+ mWmService.mSurfaceAnimationRunner.onAnimationLeashLost(mAnimationLeash, t);
mAnimationLeash = null;
reassignLayer(t);
updateSurfacePosition(t);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 451e77738745..99e7817d22ce 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2513,7 +2513,6 @@ public class WindowManagerService extends IWindowManager.Stub
if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE
&& (win.mSyncSeqId > win.mLastSeqIdSentToRelayout)) {
- win.prepareDrawHandlers();
win.markRedrawForSyncReported();
win.mLastSeqIdSentToRelayout = win.mSyncSeqId;
@@ -5692,7 +5691,9 @@ public class WindowManagerService extends IWindowManager.Stub
|| displayContent.mBaseDisplayHeight != height) {
ProtoLog.i(WM_ERROR, "FORCED DISPLAY SIZE: %dx%d", width, height);
displayContent.updateBaseDisplayMetrics(width, height,
- displayContent.mBaseDisplayDensity);
+ displayContent.mBaseDisplayDensity,
+ displayContent.mBaseDisplayPhysicalXDpi,
+ displayContent.mBaseDisplayPhysicalYDpi);
changed = true;
}
} catch (NumberFormatException ex) {
@@ -6967,13 +6968,17 @@ public class WindowManagerService extends IWindowManager.Stub
}
public void onOverlayChanged() {
- synchronized (mGlobalLock) {
- mRoot.forAllDisplays(displayContent -> {
- displayContent.getDisplayPolicy().onOverlayChangedLw();
- displayContent.updateDisplayInfo();
- });
- requestTraversal();
- }
+ // Post to display thread so it can get the latest display info.
+ mH.post(() -> {
+ synchronized (mGlobalLock) {
+ mAtmService.deferWindowLayout();
+ try {
+ mRoot.forAllDisplays(dc -> dc.getDisplayPolicy().onOverlayChanged());
+ } finally {
+ mAtmService.continueWindowLayout();
+ }
+ }
+ });
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 76ff4c0789cc..654c4602fe39 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -371,6 +371,23 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
private boolean mDragResizingChangeReported = true;
private int mResizeMode;
private boolean mRedrawForSyncReported;
+
+ /**
+ * Used to assosciate a given set of state changes sent from MSG_RESIZED
+ * with a given call to finishDrawing (does this call contain or not contain
+ * those state changes). We need to use it to handle cases like this:
+ * 1. Server changes some state, calls applyWithNextDraw
+ * 2. Client observes state change, begins drawing frame.
+ * 3. Server makes another state change, and calls applyWithNextDraw again
+ * 4. We receive finishDrawing, and it only contains the first frame
+ * but there was no way for us to know, because we no longer rely
+ * on a synchronous call to relayout before draw.
+ * We track this by storing seqIds in each draw handler, and increment
+ * this seqId every time we send MSG_RESIZED. The client sends it back
+ * with finishDrawing, and this way we can know is the client replying to
+ * the latest MSG_RESIZED or an earlier one. For a detailed discussion,
+ * examine the git commit message introducing this comment and variable.2
+ */
int mSyncSeqId = 0;
int mLastSeqIdSentToRelayout = 0;
@@ -779,75 +796,16 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
private final WindowProcessController mWpcForDisplayAreaConfigChanges;
- /**
- * We split the draw handlers in to a "pending" and "ready" list, in order to solve
- * sequencing problems. Think of it this way, let's say I update a windows orientation
- * (in configuration), and then I call applyWithNextDraw. What I'm hoping for is to
- * apply with the draw that contains the orientation change. However, since the client
- * can call finishDrawing at any time, it could be about to call a previous call to
- * finishDrawing (or maybe its already called it, we just haven't handled it). Since this
- * frame was already completed it had no time to include the orientation change we made.
- * To solve this problem we accumulate draw handlers in mPendingDrawHandlers, and then force
- * the client to call relayout. Only the frame post relayout will contain the configuration
- * change since the window has to relayout), and so in relayout we drain mPendingDrawHandlers
- * into mReadyDrawHandlers. Finally once we get to finishDrawing we know everything in
- * mReadyDrawHandlers corresponds to state which was observed by the client and we can
- * invoke the consumers.
- *
- * To see in more detail that this works, we can look at it like this:
- *
- * The client is in one of these states:
- *
- * 1. Asleep
- * 2. Traversal scheduled
- * 3. Starting traversal
- * 4. In relayout
- * 5. Already drawing
- *
- * The property we want to implement with the draw handlers is:
- * If WM code makes a change to client observable state (e.g. configuration),
- * and registers a draw handler (without releasing the WM lock in between),
- * the FIRST frame reflecting that change, will be in the Transaction passed
- * to the draw handler.
- *
- * We describe the expected sequencing in each of the possible client states.
- * We aim to "prove" that the WM can call applyWithNextDraw() with the client
- * starting in any state, and achieve the desired result.
- *
- * 1. Asleep: The client will wake up in response to MSG_RESIZED, call relayout,
- * observe the changes. Relayout will return BLAST_SYNC, and the client will
- * send the transaction to finishDrawing. Since the client was asleep. This
- * will be the first finishDrawing reflecting the change.
- * 2, 3: traversal scheduled/starting traversal: These two states can be considered
- * together. Each has two sub-states:
- * a) Traversal will call relayout. In this case we proceed like the starting
- * from asleep case.
- * b) Traversal will not call relayout. In this case, the client produced
- * frame will not include the change. Because there is no call to relayout
- * there is no call to prepareDrawHandlers() and even if the client calls
- * finish drawing the draw handler will not be invoked. We have to wait
- * on the client to receive MSG_RESIZED, and will sync on the next frame
- * 4. In relayout. In this case we are careful to prepare draw handlers and check
- * whether to return the BLAST flag at the end of relayoutWindow. This means if you
- * add a draw handler while the client is in relayout, BLAST_SYNC will be
- * immediately returned, and the client will submit the frame corresponding
- * to what returns from layout. When we prepare the draw handlers we clear the
- * flag which would later cause us to report draw for sync. Since we reported
- * sync through relayout (by luck the client was calling relayout perhaps)
- * there is no need for a MSG_RESIZED.
- * 5. Already drawing. This works much like cases 2 and 3. If there is no call to
- * finishDrawing then of course the draw handlers will not be invoked and we just
- * wait on the next frame for sync. If there is a call to finishDrawing,
- * the draw handler will not have been prepared (since we did not call relayout)
- * and we will have to wait on the next frame.
- *
- * By this logic we can see no matter which of the client states we are in when the
- * draw handler is added, it will always execute on the expected frame.
- */
- private final List<Consumer<SurfaceControl.Transaction>> mPendingDrawHandlers
- = new ArrayList<>();
- private final List<Consumer<SurfaceControl.Transaction>> mReadyDrawHandlers
- = new ArrayList<>();
+ class DrawHandler {
+ Consumer<SurfaceControl.Transaction> mConsumer;
+ int mSeqId;
+
+ DrawHandler(int seqId, Consumer<SurfaceControl.Transaction> consumer) {
+ mSeqId = seqId;
+ mConsumer = consumer;
+ }
+ }
+ private final List<DrawHandler> mDrawHandlers = new ArrayList<>();
private final Consumer<SurfaceControl.Transaction> mSeamlessRotationFinishedConsumer = t -> {
finishSeamlessRotation(t);
@@ -5677,6 +5635,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return false;
}
+ // We don't need to set the window to be relatively above IME if the IME is not visible.
+ // In case seeing the window is animating above the app transition layer because its
+ // relative layer is above the IME container on the display area but actually not necessary.
+ if (!getDisplayContent().getImeContainer().isVisible()) {
+ return false;
+ }
+
if (isChildWindow()) {
// If we are a child of the input method target we need this promotion.
if (getParentWindow().isImeLayeringTarget()) {
@@ -6011,7 +5976,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
.notifyStartingWindowDrawn(mActivityRecord);
}
- final boolean hasSyncHandlers = executeDrawHandlers(postDrawTransaction);
+ final boolean hasSyncHandlers = executeDrawHandlers(postDrawTransaction, syncSeqId);
boolean skipLayout = false;
// Control the timing to switch the appearance of window with different rotations.
@@ -6039,7 +6004,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
void immediatelyNotifyBlastSync() {
- prepareDrawHandlers();
+ // We could be more subtle with Integer.MAX_VALUE and track a seqId in the timeout.
finishDrawing(null, Integer.MAX_VALUE);
mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
if (!useBLASTSync()) return;
@@ -6096,7 +6061,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
@Override
boolean useBLASTSync() {
- return super.useBLASTSync() || (mPendingDrawHandlers.size() != 0);
+ return super.useBLASTSync() || (mDrawHandlers.size() != 0);
}
/**
@@ -6108,11 +6073,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* 2. Call applyWithNextDraw
* 3. After finishDrawing, our consumer will be passed the Transaction
* containing the buffer, and we can merge in additional operations.
- * See {@link WindowState#mPendingDrawHandlers}
+ * See {@link WindowState#mDrawHandlers}
*/
void applyWithNextDraw(Consumer<SurfaceControl.Transaction> consumer) {
- mPendingDrawHandlers.add(consumer);
mSyncSeqId++;
+ mDrawHandlers.add(new DrawHandler(mSyncSeqId, consumer));
+
requestRedrawForSync();
mWmService.mH.sendNewMessageDelayed(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this,
@@ -6120,21 +6086,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
/**
- * Called from relayout, to indicate the next "finishDrawing" will contain
- * all changes applied by the time mPendingDrawHandlers was populated.
- *
- * See {@link WindowState#mPendingDrawHandlers}
- */
- void prepareDrawHandlers() {
- mReadyDrawHandlers.addAll(mPendingDrawHandlers);
- mPendingDrawHandlers.clear();
- }
-
- /**
* Drain the draw handlers, called from finishDrawing()
* See {@link WindowState#mPendingDrawHandlers}
*/
- boolean executeDrawHandlers(SurfaceControl.Transaction t) {
+ boolean executeDrawHandlers(SurfaceControl.Transaction t, int seqId) {
boolean hadHandlers = false;
boolean applyHere = false;
if (t == null) {
@@ -6142,13 +6097,16 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
applyHere = true;
}
- for (int i = 0; i < mReadyDrawHandlers.size(); i++) {
- mReadyDrawHandlers.get(i).accept(t);
- hadHandlers = true;
+ for (int i = mDrawHandlers.size() - 1; i >= 0; i--) {
+ DrawHandler h = mDrawHandlers.get(i);
+ if (h.mSeqId <= seqId) {
+ h.mConsumer.accept(t);
+ mDrawHandlers.remove(h);
+ hadHandlers = true;
+ }
}
if (hadHandlers) {
- mReadyDrawHandlers.clear();
mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
}
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index a2e8813c998a..d2e56faa0914 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -580,7 +580,6 @@ class WindowToken extends WindowContainer<WindowState> {
.setParent(getParentSurfaceControl())
.setName(getSurfaceControl() + " - rotation-leash")
.setHidden(false)
- .setEffectLayer()
.setCallsite("WindowToken.getOrCreateFixedRotationLeash")
.build();
t.setPosition(leash, mLastSurfacePosition.x, mLastSurfacePosition.y);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
index a1cba946354f..35d4d32e568b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
@@ -30,7 +30,6 @@ import android.content.res.Resources;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.os.storage.StorageManager;
import android.provider.Settings;
import android.security.Credentials;
import android.security.KeyChain;
@@ -132,9 +131,6 @@ public class CertificateMonitor {
private final BroadcastReceiver mRootCaReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (StorageManager.inCryptKeeperBounce()) {
- return;
- }
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId());
updateInstalledCertificates(UserHandle.of(userId));
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index e18e0020407f..9a0b5c7ef5ae 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -661,6 +661,7 @@ class DevicePolicyData {
pw.println();
pw.increaseIndent();
pw.print("mPasswordOwner="); pw.println(mPasswordOwner);
+ pw.print("mPasswordTokenHandle="); pw.println(Long.toHexString(mPasswordTokenHandle));
pw.print("mUserControlDisabledPackages=");
pw.println(mUserControlDisabledPackages);
pw.print("mAppsSuspended="); pw.println(mAppsSuspended);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 17b44e3c0d64..2b64be283b36 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -278,7 +278,6 @@ import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
-import android.os.CancellationSignal;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
@@ -1799,6 +1798,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@VisibleForTesting
DevicePolicyManagerService(Injector injector) {
+ DevicePolicyManager.disableGetKeyguardDisabledFeaturesCache();
+
mInjector = injector;
mContext = Objects.requireNonNull(injector.mContext);
mHandler = new Handler(Objects.requireNonNull(injector.getMyLooper()));
@@ -1890,6 +1891,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
performPolicyVersionUpgrade();
mDeviceManagementResourcesProvider.load();
+
+ // The binder caches are not enabled until the first invalidation.
+ invalidateBinderCaches();
+ }
+
+ /**
+ * Invalidate the binder API caches. The invalidation itself does not require any
+ * locking, but this specific call should be protected by getLockObject() to ensure
+ * that the invalidation is synchronous with cached queries, for those queries that
+ * are served under getLockObject().
+ */
+ static void invalidateBinderCaches() {
+ DevicePolicyManager.invalidateBinderCaches();
}
/**
@@ -2360,11 +2374,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
private void setDeviceOwnershipSystemPropertyLocked() {
- // Still at the first stage of CryptKeeper double bounce, nothing can be learnt about
- // the real system at this point.
- if (StorageManager.inCryptKeeperBounce()) {
- return;
- }
final boolean deviceProvisioned =
mInjector.settingsGlobalGetInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0;
final boolean hasDeviceOwner = mOwners.hasDeviceOwner();
@@ -3071,6 +3080,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
!mInjector.storageManagerIsFileBasedEncryptionEnabled())) {
sendChangedNotification(userHandle);
}
+ invalidateBinderCaches();
}
private void sendChangedNotification(int userHandle) {
@@ -3392,6 +3402,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (owner != null) {
mDeviceAdminServiceController.startServiceForOwner(
owner.getPackageName(), userId, actionForLog);
+ invalidateBinderCaches();
}
}
@@ -7240,47 +7251,45 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkState(admin != null,
"Lost mode location updates can only be sent on an organization-owned device.");
mInjector.binderWithCleanCallingIdentity(() -> {
- final List<String> providers =
- mInjector.getLocationManager().getAllProviders().stream()
- .filter(mInjector.getLocationManager()::isProviderEnabled)
- .collect(Collectors.toList());
- if (providers.isEmpty()) {
- future.complete(false);
- return;
- }
-
- final CancellationSignal cancellationSignal = new CancellationSignal();
- List<String> providersWithNullLocation = new ArrayList<String>();
- for (String provider : providers) {
- mInjector.getLocationManager().getCurrentLocation(provider, cancellationSignal,
- mContext.getMainExecutor(), location -> {
- if (cancellationSignal.isCanceled()) {
- return;
- } else if (location != null) {
- sendLostModeLocationUpdate(admin, location);
- cancellationSignal.cancel();
- future.complete(true);
- } else {
- // location == null, provider wasn't able to get location, see
- // if there are more providers
- providersWithNullLocation.add(provider);
- if (providers.size() == providersWithNullLocation.size()) {
- future.complete(false);
- }
- }
- }
- );
- }
+ String[] providers = {LocationManager.FUSED_PROVIDER,
+ LocationManager.NETWORK_PROVIDER, LocationManager.GPS_PROVIDER};
+ tryRetrieveAndSendLocationUpdate(admin, future, providers, /* index= */ 0);
});
}
}
- private void sendLostModeLocationUpdate(ActiveAdmin admin, Location location) {
+ /** Send lost mode location updates recursively, in order of the list of location providers. */
+ private void tryRetrieveAndSendLocationUpdate(ActiveAdmin admin,
+ AndroidFuture<Boolean> future, String[] providers, int index) {
+ // None of the providers were able to get location, return false
+ if (index == providers.length) {
+ future.complete(false);
+ return;
+ }
+ if (mInjector.getLocationManager().isProviderEnabled(providers[index])) {
+ mInjector.getLocationManager().getCurrentLocation(providers[index],
+ /* cancellationSignal= */ null, mContext.getMainExecutor(), location -> {
+ if (location != null) {
+ mContext.sendBroadcastAsUser(
+ newLostModeLocationUpdateIntent(admin, location),
+ admin.getUserHandle());
+ future.complete(true);
+ } else {
+ tryRetrieveAndSendLocationUpdate(admin, future, providers, index + 1);
+ }
+ }
+ );
+ } else {
+ tryRetrieveAndSendLocationUpdate(admin, future, providers, index + 1);
+ }
+ }
+
+ private Intent newLostModeLocationUpdateIntent(ActiveAdmin admin, Location location) {
final Intent intent = new Intent(
DevicePolicyManager.ACTION_LOST_MODE_LOCATION_UPDATE);
intent.putExtra(DevicePolicyManager.EXTRA_LOST_MODE_LOCATION, location);
intent.setPackage(admin.info.getPackageName());
- mContext.sendBroadcastAsUser(intent, admin.getUserHandle());
+ return intent;
}
/**
@@ -8419,6 +8428,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
/**
* Gets the disabled state for features in keyguard for the given admin,
* or the aggregate of all active admins if who is null.
+ * This API is cached: invalidate with invalidateBinderCaches().
*/
@Override
public int getKeyguardDisabledFeatures(ComponentName who, int userHandle, boolean parent) {
@@ -8628,6 +8638,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return true;
}
+ /**
+ * This API is cached: invalidate with invalidateBinderCaches().
+ */
@Override
public boolean hasDeviceOwner() {
final CallerIdentity caller = getCallerIdentity();
@@ -9403,6 +9416,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
});
}
+ /**
+ * This API is cached: invalidate with invalidateBinderCaches().
+ */
@Override
public @Nullable ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent(
@NonNull UserHandle userHandle) {
@@ -9468,6 +9484,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return UserHandle.USER_NULL;
}
+ /**
+ * This API is cached: invalidate with invalidateBinderCaches().
+ */
@Override
public boolean isOrganizationOwnedDeviceWithManagedProfile() {
if (!mHasFeature) {
@@ -13053,6 +13072,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
mConstants = loadConstants();
+ invalidateBinderCaches();
mInjector.binderWithCleanCallingIdentity(() -> {
final Intent intent = new Intent(
@@ -13213,6 +13233,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
.createEvent(DevicePolicyEnums.SEPARATE_PROFILE_CHALLENGE_CHANGED)
.setBoolean(isSeparateProfileChallengeEnabled(userId))
.write();
+ invalidateBinderCaches();
}
@Override
@@ -14636,6 +14657,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ /**
+ * This API is cached: invalidate with invalidateBinderCaches().
+ */
@Override
public CharSequence getDeviceOwnerOrganizationName() {
if (!mHasFeature) {
@@ -14650,6 +14674,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ /**
+ * This API is cached: invalidate with invalidateBinderCaches().
+ */
@Override
public CharSequence getOrganizationNameForUser(int userHandle) {
if (!mHasFeature) {
@@ -15735,6 +15762,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// available after next boot.
}
+ /**
+ * This API is cached: invalidate with invalidateBinderCaches().
+ */
@Override
public boolean isNetworkLoggingEnabled(@Nullable ComponentName admin,
@NonNull String packageName) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index b0fdd723347f..37da7b428148 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -217,10 +217,9 @@ class Owners {
Slog.w(TAG, String.format("User %d has both DO and PO, which is not supported",
getDeviceOwnerUserId()));
}
- pushToPackageManagerLocked();
+
+ notifyChangeLocked();
pushToActivityTaskManagerLocked();
- pushToActivityManagerLocked();
- pushToAppOpsLocked();
for (ArrayMap.Entry<String, List<String>> entry :
mDeviceOwnerProtectedPackages.entrySet()) {
@@ -230,6 +229,21 @@ class Owners {
}
}
+ // Notify interested parties that things have changed. This does not notify the
+ // ActivityTaskManager.
+ private void notifyChangeLocked() {
+ pushToDevicePolicyManager();
+ pushToPackageManagerLocked();
+ pushToActivityManagerLocked();
+ pushToAppOpsLocked();
+ }
+
+ private void pushToDevicePolicyManager() {
+ // Not every change here must invalidate the DPM caches, but there is no harm in
+ // invalidating the caches unnecessarily, provided the invalidation is infrequent.
+ DevicePolicyManagerService.invalidateBinderCaches();
+ }
+
private void pushToPackageManagerLocked() {
final SparseArray<String> po = new SparseArray<>();
for (int i = mProfileOwners.size() - 1; i >= 0; i--) {
@@ -344,10 +358,8 @@ class Owners {
mDeviceOwnerUserId = userId;
mUserManagerInternal.setDeviceManaged(true);
- pushToPackageManagerLocked();
+ notifyChangeLocked();
pushToActivityTaskManagerLocked();
- pushToActivityManagerLocked();
- pushToAppOpsLocked();
}
}
@@ -364,10 +376,8 @@ class Owners {
mDeviceOwnerUserId = UserHandle.USER_NULL;
mUserManagerInternal.setDeviceManaged(false);
- pushToPackageManagerLocked();
+ notifyChangeLocked();
pushToActivityTaskManagerLocked();
- pushToActivityManagerLocked();
- pushToAppOpsLocked();
}
}
@@ -378,9 +388,7 @@ class Owners {
/* userRestrictionsMigrated =*/ true, /* remoteBugreportUri =*/ null,
/* remoteBugreportHash =*/ null, /* isOrganizationOwnedDevice =*/ false));
mUserManagerInternal.setUserManaged(userId, true);
- pushToPackageManagerLocked();
- pushToActivityManagerLocked();
- pushToAppOpsLocked();
+ notifyChangeLocked();
}
}
@@ -388,9 +396,7 @@ class Owners {
synchronized (mLock) {
mProfileOwners.remove(userId);
mUserManagerInternal.setUserManaged(userId, false);
- pushToPackageManagerLocked();
- pushToActivityManagerLocked();
- pushToAppOpsLocked();
+ notifyChangeLocked();
}
}
@@ -402,9 +408,7 @@ class Owners {
ownerInfo.remoteBugreportHash, /* isOrganizationOwnedDevice =*/
ownerInfo.isOrganizationOwnedDevice);
mProfileOwners.put(userId, newOwnerInfo);
- pushToPackageManagerLocked();
- pushToActivityManagerLocked();
- pushToAppOpsLocked();
+ notifyChangeLocked();
}
}
@@ -430,10 +434,8 @@ class Owners {
mDeviceOwnerProtectedPackages.put(
mDeviceOwner.packageName, previousProtectedPackages);
}
- pushToPackageManagerLocked();
+ notifyChangeLocked();
pushToActivityTaskManagerLocked();
- pushToActivityManagerLocked();
- pushToAppOpsLocked();
}
}
@@ -765,6 +767,7 @@ class Owners {
if (DEBUG) {
Log.d(TAG, "Writing to device owner file");
}
+ pushToDevicePolicyManager();
new DeviceOwnerReadWriter().writeToFileLocked();
}
}
@@ -774,6 +777,7 @@ class Owners {
if (DEBUG) {
Log.d(TAG, "Writing to profile owner file for user " + userId);
}
+ pushToDevicePolicyManager();
new ProfileOwnerReadWriter(userId).writeToFileLocked();
}
}
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 1cdcbd87c1f5..66524edf61ed 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -370,6 +370,33 @@ public final class PrintManagerService extends SystemService {
}
@Override
+ public boolean isPrintServiceEnabled(ComponentName service, int userId) {
+ final String[] packages = mContext.getPackageManager().getPackagesForUid(
+ Binder.getCallingUid());
+ boolean matchCalling = false;
+ for (int i = 0; i < packages.length; i++) {
+ if (packages[i].equals(service.getPackageName())) {
+ matchCalling = true;
+ break;
+ }
+ }
+ if (!matchCalling) {
+ // Do not reveal any information about other package services.
+ throw new SecurityException("PrintService does not share UID with caller.");
+ }
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final UserState userState;
+ synchronized (mLock) {
+ // Only the current group members can check print services.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+ return false;
+ }
+ userState = getOrCreateUserStateLocked(resolvedUserId, false);
+ }
+ return userState.isPrintServiceEnabled(service);
+ }
+
+ @Override
public List<RecommendationInfo> getPrintServiceRecommendations(int userId) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS, null);
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index b93c519ec8e4..774f62d44045 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -63,7 +63,6 @@ import android.print.PrinterInfo;
import android.printservice.PrintServiceInfo;
import android.printservice.recommendation.IRecommendationsChangeListener;
import android.printservice.recommendation.RecommendationInfo;
-import android.provider.DocumentsContract;
import android.provider.Settings;
import android.service.print.CachedPrintJobProto;
import android.service.print.InstalledPrintServiceProto;
@@ -438,6 +437,15 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
}
}
+ public boolean isPrintServiceEnabled(@NonNull ComponentName serviceName) {
+ synchronized (mLock) {
+ if (mDisabledServices.contains(serviceName)) {
+ return false;
+ }
+ return true;
+ }
+ }
+
/**
* @return The currently known print service recommendations
*/
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 66e840b5120b..bbc28d78d6f2 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -54,7 +54,7 @@ public final class ProfcollectForwardingService extends SystemService {
private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG);
- private static final long BG_PROCESS_PERIOD = TimeUnit.DAYS.toMillis(1); // every 1 day.
+ private static final long BG_PROCESS_PERIOD = TimeUnit.HOURS.toMillis(4); // every 4 hours.
private IProfCollectd mIProfcollect;
private static ProfcollectForwardingService sSelfService;
diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
index 7017440a86bb..7b152247eb9c 100644
--- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
+++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
@@ -34,7 +34,6 @@ import com.android.server.pm.test.override.PackageManagerComponentLabelIconOverr
import com.android.server.testutils.TestHandler
import com.android.server.testutils.mock
import com.android.server.testutils.mockThrowOnUnmocked
-import com.android.server.testutils.spy
import com.android.server.testutils.whenever
import com.android.server.wm.ActivityTaskManagerInternal
import com.google.common.truth.Truth.assertThat
@@ -46,13 +45,9 @@ import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.mockito.Mockito.any
import org.mockito.Mockito.anyInt
-import org.mockito.Mockito.clearInvocations
-import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.intThat
-import org.mockito.Mockito.never
import org.mockito.Mockito.same
-import org.mockito.Mockito.verify
import org.testng.Assert.assertThrows
import java.io.File
import java.util.UUID
@@ -365,7 +360,7 @@ class PackageManagerComponentLabelIconOverrideTest {
val mockActivityTaskManager: ActivityTaskManagerInternal = mockThrowOnUnmocked {
whenever(this.isCallerRecents(anyInt())) { false }
}
- val mockAppsFilter: AppsFilter = mockThrowOnUnmocked {
+ val mockAppsFilter: AppsFilterImpl = mockThrowOnUnmocked {
whenever(this.shouldFilterApplication(anyInt(), any<PackageSetting>(),
any<PackageSetting>(), anyInt())) { false }
whenever(this.snapshot()) { this@mockThrowOnUnmocked }
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 4a51e41b1dc5..c9523ec16b8f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -58,6 +58,7 @@ import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION;
import static com.android.server.alarm.AlarmManagerService.ACTIVE_INDEX;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.APP_STANDBY_BUCKET_CHANGED;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHARGING_STATUS_CHANGED;
+import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.EXACT_ALARM_DENY_LIST_PACKAGES_ADDED;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.EXACT_ALARM_DENY_LIST_PACKAGES_REMOVED;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES;
@@ -1044,9 +1045,19 @@ public class AlarmManagerServiceTest {
final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
verify(mService.mHandler, atLeastOnce()).sendMessageAtTime(messageCaptor.capture(),
anyLong());
- final Message lastMessage = messageCaptor.getValue();
- assertEquals("Unexpected message send to handler", what, lastMessage.what);
- mService.mHandler.handleMessage(lastMessage);
+
+ Message expectedMessage = null;
+ final ArrayList<Integer> sentMessages = new ArrayList<>();
+ for (Message sentMessage : messageCaptor.getAllValues()) {
+ if (sentMessage.what == what) {
+ expectedMessage = sentMessage;
+ }
+ sentMessages.add(sentMessage.what);
+ }
+
+ assertNotNull("Unexpected messages sent to handler. Expected: " + what + ", sent: "
+ + sentMessages, expectedMessage);
+ mService.mHandler.handleMessage(expectedMessage);
}
@Test
@@ -2109,16 +2120,16 @@ public class AlarmManagerServiceTest {
public void hasScheduleExactAlarmBinderCallNotDenyListed() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
- mockExactAlarmPermissionGrant(true, false, MODE_DEFAULT);
+ mockScheduleExactAlarmState(true, false, MODE_DEFAULT);
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
- mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
+ mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
- mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
+ mockScheduleExactAlarmState(true, false, MODE_ERRORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
- mockExactAlarmPermissionGrant(true, false, MODE_IGNORED);
+ mockScheduleExactAlarmState(true, false, MODE_IGNORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
}
@@ -2126,16 +2137,16 @@ public class AlarmManagerServiceTest {
public void hasScheduleExactAlarmBinderCallDenyListed() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
- mockExactAlarmPermissionGrant(true, true, MODE_ERRORED);
+ mockScheduleExactAlarmState(true, true, MODE_ERRORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
- mockExactAlarmPermissionGrant(true, true, MODE_DEFAULT);
+ mockScheduleExactAlarmState(true, true, MODE_DEFAULT);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
- mockExactAlarmPermissionGrant(true, true, MODE_IGNORED);
+ mockScheduleExactAlarmState(true, true, MODE_IGNORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
- mockExactAlarmPermissionGrant(true, true, MODE_ALLOWED);
+ mockScheduleExactAlarmState(true, true, MODE_ALLOWED);
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
}
@@ -2148,13 +2159,13 @@ public class AlarmManagerServiceTest {
public void hasScheduleExactAlarmBinderCallNotDeclared() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
- mockExactAlarmPermissionGrant(false, false, MODE_DEFAULT);
+ mockScheduleExactAlarmState(false, false, MODE_DEFAULT);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
- mockExactAlarmPermissionGrant(false, false, MODE_ALLOWED);
+ mockScheduleExactAlarmState(false, false, MODE_ALLOWED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
- mockExactAlarmPermissionGrant(false, true, MODE_ALLOWED);
+ mockScheduleExactAlarmState(false, true, MODE_ALLOWED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
}
@@ -2162,10 +2173,17 @@ public class AlarmManagerServiceTest {
public void canScheduleExactAlarmsBinderCallChangeDisabled() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false);
- mockExactAlarmPermissionGrant(false, true, MODE_DEFAULT);
+ // canScheduleExactAlarms should be true regardless of any permission state.
+ mockUseExactAlarmState(true);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
- mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
+ mockUseExactAlarmState(false);
+ assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
+
+ mockScheduleExactAlarmState(false, true, MODE_DEFAULT);
+ assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
+
+ mockScheduleExactAlarmState(true, false, MODE_ERRORED);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
}
@@ -2173,44 +2191,45 @@ public class AlarmManagerServiceTest {
public void canScheduleExactAlarmsBinderCall() throws RemoteException {
// Policy permission is denied in setUp().
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
+ mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true);
// No permission, no exemption.
- mockExactAlarmPermissionGrant(true, true, MODE_DEFAULT);
+ mockScheduleExactAlarmState(true, true, MODE_DEFAULT);
assertFalse(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// No permission, no exemption.
- mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
+ mockScheduleExactAlarmState(true, false, MODE_ERRORED);
assertFalse(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// Policy permission only, no exemption.
- mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
- doReturn(PermissionChecker.PERMISSION_GRANTED).when(
- () -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
- eq(Manifest.permission.USE_EXACT_ALARM), anyInt(), eq(TEST_CALLING_UID),
- eq(TEST_CALLING_PACKAGE)));
+ mockScheduleExactAlarmState(true, false, MODE_ERRORED);
+ mockUseExactAlarmState(true);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
- // Permission, no exemption.
- mockExactAlarmPermissionGrant(true, false, MODE_DEFAULT);
+ mockUseExactAlarmState(false);
+
+ // User permission only, no exemption.
+ mockScheduleExactAlarmState(true, false, MODE_DEFAULT);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
- // Permission, no exemption.
- mockExactAlarmPermissionGrant(true, true, MODE_ALLOWED);
+ // User permission only, no exemption.
+ mockScheduleExactAlarmState(true, true, MODE_ALLOWED);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// No permission, exemption.
- mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
+ mockScheduleExactAlarmState(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(TEST_CALLING_UID)).thenReturn(true);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// No permission, exemption.
- mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
+ mockScheduleExactAlarmState(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(TEST_CALLING_UID)).thenReturn(false);
doReturn(true).when(() -> UserHandle.isCore(TEST_CALLING_UID));
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
- // Both permission and exemption.
- mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
+ // Both permissions and exemption.
+ mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
+ mockUseExactAlarmState(true);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
}
@@ -2237,6 +2256,8 @@ public class AlarmManagerServiceTest {
verify(mService, never()).hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE,
TEST_CALLING_UID);
+ verify(mService, never()).hasUseExactAlarmInternal(TEST_CALLING_PACKAGE,
+ TEST_CALLING_UID);
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
}
@@ -2313,7 +2334,7 @@ public class AlarmManagerServiceTest {
public void alarmClockBinderCall() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
- mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
+ mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
final PendingIntent alarmPi = getNewMockPendingIntent();
final AlarmManager.AlarmClockInfo alarmClock = mock(AlarmManager.AlarmClockInfo.class);
@@ -2335,7 +2356,7 @@ public class AlarmManagerServiceTest {
assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
}
- private void mockExactAlarmPermissionGrant(boolean declared, boolean denyList, int mode) {
+ private void mockScheduleExactAlarmState(boolean declared, boolean denyList, int mode) {
String[] requesters = declared ? new String[]{TEST_CALLING_PACKAGE} : EmptyArray.STRING;
when(mPermissionManagerInternal.getAppOpPermissionPackages(SCHEDULE_EXACT_ALARM))
.thenReturn(requesters);
@@ -2350,12 +2371,21 @@ public class AlarmManagerServiceTest {
TEST_CALLING_PACKAGE)).thenReturn(mode);
}
+ private void mockUseExactAlarmState(boolean granted) {
+ final int result = granted ? PermissionChecker.PERMISSION_GRANTED
+ : PermissionChecker.PERMISSION_HARD_DENIED;
+ doReturn(result).when(
+ () -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
+ eq(Manifest.permission.USE_EXACT_ALARM), anyInt(), eq(TEST_CALLING_UID),
+ eq(TEST_CALLING_PACKAGE)));
+ }
+
@Test
public void alarmClockBinderCallWithoutPermission() throws RemoteException {
setDeviceConfigBoolean(KEY_CRASH_NON_CLOCK_APPS, true);
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
- mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
+ mockScheduleExactAlarmState(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
final PendingIntent alarmPi = getNewMockPendingIntent();
@@ -2377,7 +2407,7 @@ public class AlarmManagerServiceTest {
public void exactBinderCallWithPermission() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
- mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
+ mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
final PendingIntent alarmPi = getNewMockPendingIntent();
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
0, alarmPi, null, null, null, null);
@@ -2401,7 +2431,7 @@ public class AlarmManagerServiceTest {
public void exactBinderCallWithAllowlist() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
// If permission is denied, only then allowlist will be checked.
- mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
+ mockScheduleExactAlarmState(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
final PendingIntent alarmPi = getNewMockPendingIntent();
@@ -2421,7 +2451,7 @@ public class AlarmManagerServiceTest {
public void exactAllowWhileIdleBinderCallWithPermission() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
- mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
+ mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
final PendingIntent alarmPi = getNewMockPendingIntent();
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
FLAG_ALLOW_WHILE_IDLE, alarmPi, null, null, null, null);
@@ -2444,7 +2474,7 @@ public class AlarmManagerServiceTest {
public void exactAllowWhileIdleBinderCallWithAllowlist() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
// If permission is denied, only then allowlist will be checked.
- mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
+ mockScheduleExactAlarmState(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
final PendingIntent alarmPi = getNewMockPendingIntent();
@@ -2471,7 +2501,7 @@ public class AlarmManagerServiceTest {
setDeviceConfigBoolean(KEY_CRASH_NON_CLOCK_APPS, true);
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
- mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
+ mockScheduleExactAlarmState(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(false);
final PendingIntent alarmPi = getNewMockPendingIntent();
@@ -2503,6 +2533,7 @@ public class AlarmManagerServiceTest {
FLAG_ALLOW_WHILE_IDLE, alarmPi, null, null, null, null);
verify(mService, never()).hasScheduleExactAlarmInternal(anyString(), anyInt());
+ verify(mService, never()).hasUseExactAlarmInternal(anyString(), anyInt());
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -2520,7 +2551,7 @@ public class AlarmManagerServiceTest {
public void binderCallWithUserAllowlist() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
- mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
+ mockScheduleExactAlarmState(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
when(mAppStateTracker.isUidPowerSaveUserExempt(TEST_CALLING_UID)).thenReturn(true);
@@ -2792,7 +2823,7 @@ public class AlarmManagerServiceTest {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ALLOWED);
- mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
+ mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
assertAndHandleMessageSync(REMOVE_EXACT_ALARMS);
@@ -2805,7 +2836,7 @@ public class AlarmManagerServiceTest {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false);
mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ALLOWED);
- mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
+ mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
@@ -2818,7 +2849,7 @@ public class AlarmManagerServiceTest {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false);
mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ERRORED);
- mockExactAlarmPermissionGrant(true, true, MODE_DEFAULT);
+ mockScheduleExactAlarmState(true, true, MODE_DEFAULT);
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
@@ -2834,7 +2865,7 @@ public class AlarmManagerServiceTest {
when(mActivityManagerInternal.getBootTimeTempAllowListDuration()).thenReturn(durationMs);
mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ERRORED);
- mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
+ mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -3036,48 +3067,6 @@ public class AlarmManagerServiceTest {
}
@Test
- public void refreshExactAlarmCandidatesRemovesExactAlarmsIfNeeded() {
- mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
-
- mService.mExactAlarmCandidates = new ArraySet<>(new Integer[]{1, 2, 5});
- final String[] updatedRequesters = new String[]{"p11", "p2", "p9"};
- final Integer[] appIds = new Integer[]{11, 2, 9};
- registerAppIds(updatedRequesters, appIds);
-
- when(mPermissionManagerInternal.getAppOpPermissionPackages(
- SCHEDULE_EXACT_ALARM)).thenReturn(updatedRequesters);
-
- final PendingIntent exactAppId1 = getNewMockPendingIntent();
- setTestAlarm(ELAPSED_REALTIME, 0, 0, exactAppId1, 0, 0,
- UserHandle.getUid(TEST_CALLING_USER, 1), null);
-
- final PendingIntent exactAppId2 = getNewMockPendingIntent();
- setTestAlarm(ELAPSED_REALTIME, 0, 0, exactAppId2, 0, 0,
- UserHandle.getUid(TEST_CALLING_USER, 2), null);
-
- final PendingIntent exactAppId5 = getNewMockPendingIntent();
- setTestAlarm(ELAPSED_REALTIME, 0, 0, exactAppId5, 0, 0,
- UserHandle.getUid(TEST_CALLING_USER, 5), null);
-
- final PendingIntent inexactAppId5 = getNewMockPendingIntent();
- setTestAlarm(ELAPSED_REALTIME, 0, 23, inexactAppId5, 0, 0,
- UserHandle.getUid(TEST_CALLING_USER, 5), null);
-
- assertEquals(4, mService.mAlarmStore.size());
-
- mService.refreshExactAlarmCandidates();
- // App ids 1 and 5 lost the permission, so there alarms should be removed.
-
- final ArrayList<Alarm> remaining = mService.mAlarmStore.asList();
- assertEquals(2, remaining.size());
-
- assertTrue("Inexact alarm removed",
- remaining.removeIf(a -> a.matches(inexactAppId5, null)));
- assertTrue("Alarm from app id 2 removed",
- remaining.removeIf(a -> a.matches(exactAppId2, null)));
- }
-
- @Test
public void refreshExactAlarmCandidatesOnPackageAdded() {
final String[] exactAlarmRequesters = new String[]{"p11", "p2", "p9"};
final Integer[] appIds = new Integer[]{11, 2, 9};
@@ -3130,6 +3119,78 @@ public class AlarmManagerServiceTest {
}
@Test
+ public void exactAlarmsRemovedIfNeededOnPackageReplaced() {
+ mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
+ mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true);
+
+ final int otherUid = 2313;
+ final String otherPackage = "p1";
+
+ final PendingIntent exactAlarm1 = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME, 1, 0, exactAlarm1, 0, 0, TEST_CALLING_UID,
+ TEST_CALLING_PACKAGE, null);
+
+ final PendingIntent exactAlarm2 = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME, 2, 0, exactAlarm2, 0, 0, TEST_CALLING_UID,
+ TEST_CALLING_PACKAGE, null);
+
+ final PendingIntent otherPackageExactAlarm = getNewMockPendingIntent(otherUid,
+ otherPackage);
+ setTestAlarm(ELAPSED_REALTIME, 0, 0, otherPackageExactAlarm, 0, 0, otherUid, otherPackage,
+ null);
+
+ final PendingIntent inexactAlarm = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME, 0, 23, inexactAlarm, 0, 0, TEST_CALLING_UID,
+ TEST_CALLING_PACKAGE, null);
+
+ final PendingIntent otherPackageInexactAlarm = getNewMockPendingIntent(otherUid,
+ otherPackage);
+ setTestAlarm(ELAPSED_REALTIME, 0, 23, otherPackageInexactAlarm, 0, 0, otherUid,
+ otherPackage, null);
+
+ assertEquals(5, mService.mAlarmStore.size());
+
+ final Intent packageReplacedIntent = new Intent(Intent.ACTION_PACKAGE_ADDED)
+ .setData(Uri.fromParts("package", TEST_CALLING_PACKAGE, null))
+ .putExtra(Intent.EXTRA_UID, TEST_CALLING_UID)
+ .putExtra(Intent.EXTRA_REPLACING, true);
+
+ mockUseExactAlarmState(false);
+ mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
+ mPackageChangesReceiver.onReceive(mMockContext, packageReplacedIntent);
+ assertAndHandleMessageSync(CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE);
+
+ // user permission is granted, no alarms should be removed
+ assertEquals(5, mService.mAlarmStore.size());
+
+ mockUseExactAlarmState(true);
+ mockScheduleExactAlarmState(true, false, MODE_ERRORED);
+ mPackageChangesReceiver.onReceive(mMockContext, packageReplacedIntent);
+ assertAndHandleMessageSync(CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE);
+
+ // policy permission is granted, no alarms should be removed
+ assertEquals(5, mService.mAlarmStore.size());
+
+ mockUseExactAlarmState(false);
+ mockScheduleExactAlarmState(true, false, MODE_ERRORED);
+ mPackageChangesReceiver.onReceive(mMockContext, packageReplacedIntent);
+ assertAndHandleMessageSync(CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE);
+
+ // no permission is granted, exact alarms should be removed
+ assertEquals(3, mService.mAlarmStore.size());
+
+ List<Alarm> remaining = mService.mAlarmStore.asList();
+ assertTrue("Inexact alarm removed", remaining.removeIf(a -> a.matches(inexactAlarm, null)));
+
+ assertEquals(2, remaining.size());
+ assertTrue("Alarms from other package removed",
+ remaining.removeIf(a -> a.matches(otherPackageExactAlarm, null)
+ || a.matches(otherPackageInexactAlarm, null)));
+
+ assertEquals(0, remaining.size());
+ }
+
+ @Test
public void alarmScheduledAtomPushed() {
for (int i = 0; i < 10; i++) {
final PendingIntent pi = getNewMockPendingIntent();
@@ -3187,6 +3248,28 @@ public class AlarmManagerServiceTest {
bOptions.getTemporaryAppAllowlistReasonCode());
}
+ @Test
+ public void hasUseExactAlarmPermission() {
+ mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true);
+
+ mockUseExactAlarmState(true);
+ assertTrue(mService.hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
+
+ mockUseExactAlarmState(false);
+ assertFalse(mService.hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
+ }
+
+ @Test
+ public void hasUseExactAlarmPermissionChangeDisabled() {
+ mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, false);
+
+ mockUseExactAlarmState(true);
+ assertFalse(mService.hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
+
+ mockUseExactAlarmState(false);
+ assertFalse(mService.hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
+ }
+
@After
public void tearDown() {
if (mMockingSession != null) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
index 47d4c8d9af46..47b715ebd7c0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -579,6 +579,7 @@ public final class BackgroundRestrictionTest {
DeviceConfigSession<Boolean> bgPromptFgsWithNotiToBgRestricted = null;
DeviceConfigSession<Long> bgNotificationMinInterval = null;
DeviceConfigSession<Integer> bgBatteryExemptionTypes = null;
+ DeviceConfigSession<Boolean> bgCurrentDrainDecoupleThresholds = null;
mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
@@ -648,6 +649,13 @@ public final class BackgroundRestrictionTest {
R.integer.config_bg_current_drain_exempted_types));
bgBatteryExemptionTypes.set(0);
+ bgCurrentDrainDecoupleThresholds = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS,
+ DeviceConfig::getBoolean,
+ AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD);
+ bgCurrentDrainDecoupleThresholds.set(true);
+
mCurrentTimeMillis = 10_000L;
doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
@@ -785,6 +793,11 @@ public final class BackgroundRestrictionTest {
anyInt(), anyInt());
});
+ // Pretend we have the standby buckets set above.
+ doReturn(STANDBY_BUCKET_RESTRICTED)
+ .when(mAppStandbyInternal)
+ .getAppStandbyBucket(eq(testPkgName), eq(testUser), anyLong(), anyBoolean());
+
// Sleep a while and set a higher drain
Thread.sleep(windowMs);
clearInvocations(mInjector.getAppStandbyInternal());
@@ -921,6 +934,11 @@ public final class BackgroundRestrictionTest {
// Expected.
}
+ // Reset the standby bucket.
+ doReturn(STANDBY_BUCKET_RARE)
+ .when(mAppStandbyInternal)
+ .getAppStandbyBucket(eq(testPkgName), eq(testUser), anyLong(), anyBoolean());
+
// Turn OFF the FAS.
listener.mLatchHolder[0] = new CountDownLatch(1);
clearInvocations(mInjector.getAppStandbyInternal());
@@ -930,6 +948,99 @@ public final class BackgroundRestrictionTest {
// It'll go back to restricted bucket because it used to behave poorly.
listener.verify(timeout, testUid, testPkgName, RESTRICTION_LEVEL_RESTRICTED_BUCKET);
verifyRestrictionLevel(RESTRICTION_LEVEL_RESTRICTED_BUCKET, testPkgName, testUid);
+
+ clearInvocations(mInjector.getAppStandbyInternal());
+ // Trigger user interaction.
+ runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
+ new double[]{restrictBucketThresholdMah - 1, 0},
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
+ () -> {
+ doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
+ doReturn(mCurrentTimeMillis + windowMs)
+ .when(stats).getStatsEndTimestamp();
+ mCurrentTimeMillis += windowMs + 1;
+ mIdleStateListener.onUserInteractionStarted(testPkgName, testUser);
+ waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
+ // It should have been back to normal.
+ listener.verify(timeout, testUid, testPkgName,
+ RESTRICTION_LEVEL_ADAPTIVE_BUCKET);
+ verify(mInjector.getAppStandbyInternal(), atLeast(1)).maybeUnrestrictApp(
+ eq(testPkgName),
+ eq(testUser),
+ eq(REASON_MAIN_USAGE),
+ eq(REASON_SUB_USAGE_USER_INTERACTION),
+ eq(REASON_MAIN_USAGE),
+ eq(REASON_SUB_USAGE_USER_INTERACTION));
+ });
+
+ bgCurrentDrainDecoupleThresholds.set(true);
+ clearInvocations(mInjector.getAppStandbyInternal());
+
+ // Go to the threshold right away.
+ runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
+ new double[]{0, restrictBucketThresholdMah - 1},
+ new double[]{bgRestrictedThresholdMah + 1, 0}, zeros, zeros,
+ () -> {
+ doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
+ doReturn(mCurrentTimeMillis + windowMs)
+ .when(stats).getStatsEndTimestamp();
+ mCurrentTimeMillis += windowMs + 1;
+ // We won't change restriction level automatically because it needs
+ // user consent.
+ try {
+ listener.verify(timeout, testUid, testPkgName,
+ RESTRICTION_LEVEL_BACKGROUND_RESTRICTED);
+ fail("There shouldn't be level change event like this");
+ } catch (Exception e) {
+ // Expected.
+ }
+ verify(mInjector.getAppStandbyInternal(), never()).setAppStandbyBucket(
+ eq(testPkgName),
+ eq(STANDBY_BUCKET_RARE),
+ eq(testUser),
+ anyInt(), anyInt());
+ // We should have requested to goto background restricted level.
+ verify(mBgRestrictionController, times(1)).handleRequestBgRestricted(
+ eq(testPkgName),
+ eq(testUid));
+ // Verify we have the notification posted now because its FGS is invisible.
+ checkNotificationShown(new String[] {testPkgName}, atLeast(1), true);
+ });
+
+ bgCurrentDrainDecoupleThresholds.set(false);
+ clearInvocations(mInjector.getAppStandbyInternal());
+ clearInvocations(mBgRestrictionController);
+
+ // Go to the threshold right away, but this time, it shouldn't even request to goto
+ // bg restricted level because it requires to be in restricted bucket before that.
+ runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
+ new double[]{0, restrictBucketThresholdMah - 1},
+ new double[]{bgRestrictedThresholdMah + 1, 0}, zeros, zeros,
+ () -> {
+ doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
+ doReturn(mCurrentTimeMillis + windowMs)
+ .when(stats).getStatsEndTimestamp();
+ mCurrentTimeMillis += windowMs + 1;
+ // We won't change restriction level automatically because it needs
+ // user consent.
+ try {
+ listener.verify(timeout, testUid, testPkgName,
+ RESTRICTION_LEVEL_BACKGROUND_RESTRICTED);
+ fail("There shouldn't be level change event like this");
+ } catch (Exception e) {
+ // Expected.
+ }
+ verify(mInjector.getAppStandbyInternal(), never()).setAppStandbyBucket(
+ eq(testPkgName),
+ eq(STANDBY_BUCKET_RARE),
+ eq(testUser),
+ anyInt(), anyInt());
+ // We should NOT have requested to goto background restricted level.
+ verify(mBgRestrictionController, never()).handleRequestBgRestricted(
+ eq(testPkgName),
+ eq(testUid));
+ });
+
} finally {
closeIfNotNull(bgCurrentDrainMonitor);
closeIfNotNull(bgCurrentDrainWindow);
@@ -938,6 +1049,7 @@ public final class BackgroundRestrictionTest {
closeIfNotNull(bgPromptFgsWithNotiToBgRestricted);
closeIfNotNull(bgNotificationMinInterval);
closeIfNotNull(bgBatteryExemptionTypes);
+ closeIfNotNull(bgCurrentDrainDecoupleThresholds);
}
}
@@ -955,6 +1067,8 @@ public final class BackgroundRestrictionTest {
final int testUid2 = UserHandle.getUid(testUser2, TEST_PACKAGE_APPID_BASE + testPkgIndex2);
final int testPid2 = 1235;
+ final int fgsNotificationId = 1000;
+
final long windowMs = 2_000;
final long thresholdMs = 1_000;
final long shortMs = 100;
@@ -962,6 +1076,7 @@ public final class BackgroundRestrictionTest {
DeviceConfigSession<Boolean> longRunningFGSMonitor = null;
DeviceConfigSession<Long> longRunningFGSWindow = null;
DeviceConfigSession<Long> longRunningFGSThreshold = null;
+ DeviceConfigSession<Boolean> longRunningFGSWithNotification = null;
try {
longRunningFGSMonitor = new DeviceConfigSession<>(
@@ -985,6 +1100,13 @@ public final class BackgroundRestrictionTest {
AppFGSPolicy.DEFAULT_BG_FGS_LONG_RUNNING_THRESHOLD);
longRunningFGSThreshold.set(thresholdMs);
+ longRunningFGSWithNotification = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ ConstantsObserver.KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING,
+ DeviceConfig::getBoolean,
+ ConstantsObserver.DEFAULT_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING);
+ longRunningFGSWithNotification.set(true);
+
// Basic case
mAppFGSTracker.onForegroundServiceStateChanged(testPkgName1, testUid1,
testPid1, true);
@@ -1084,10 +1206,42 @@ public final class BackgroundRestrictionTest {
mAppFGSTracker.onForegroundServiceStateChanged(testPkgName1, testUid1,
testPid1, false);
checkNotificationGone(testPkgName1, timeout(windowMs), notificationId);
+
+ // Start over with the flag to not show prompt when it has an active notification.
+ clearInvocations(mInjector.getNotificationManager());
+ mBgRestrictionController.resetRestrictionSettings();
+ longRunningFGSWithNotification.set(false);
+
+ // Start an FGS with notification.
+ mAppFGSTracker.onForegroundServiceStateChanged(testPkgName1, testUid1,
+ testPid1, true);
+ mAppFGSTracker.onForegroundServiceNotificationUpdated(
+ testPkgName1, testUid1, fgsNotificationId);
+ mAppFGSTracker.mNotificationListener.onNotificationPosted(new StatusBarNotification(
+ testPkgName1, null, fgsNotificationId, null, testUid1, testPid1,
+ new Notification(), UserHandle.of(testUser1), null, mCurrentTimeMillis), null);
+
+ // Verify we won't prompt the user because it has a visible FGS notification.
+ checkNotificationShown(
+ new String[] {testPkgName1}, timeout(windowMs * 2).times(0), false);
+
+ // Pretend we have the notification dismissed.
+ mAppFGSTracker.onForegroundServiceNotificationUpdated(
+ testPkgName1, testUid1, -fgsNotificationId);
+
+ // Verify we have the notification.
+ notificationId = checkNotificationShown(
+ new String[] {testPkgName1}, timeout(windowMs * 2).times(2), true)[0];
+
+ // Stop the FGS.
+ mAppFGSTracker.onForegroundServiceStateChanged(testPkgName1, testUid1,
+ testPid1, false);
+ checkNotificationGone(testPkgName1, timeout(windowMs), notificationId);
} finally {
closeIfNotNull(longRunningFGSMonitor);
closeIfNotNull(longRunningFGSWindow);
closeIfNotNull(longRunningFGSThreshold);
+ closeIfNotNull(longRunningFGSWithNotification);
}
}
@@ -1113,6 +1267,7 @@ public final class BackgroundRestrictionTest {
DeviceConfigSession<Long> longRunningFGSThreshold = null;
DeviceConfigSession<Long> mediaPlaybackFGSThreshold = null;
DeviceConfigSession<Long> locationFGSThreshold = null;
+ DeviceConfigSession<Boolean> longRunningFGSWithNotification = null;
doReturn(testPkgName1).when(mInjector).getPackageName(testPid1);
doReturn(testPkgName2).when(mInjector).getPackageName(testPid2);
@@ -1153,6 +1308,13 @@ public final class BackgroundRestrictionTest {
AppFGSPolicy.DEFAULT_BG_FGS_LOCATION_THRESHOLD);
locationFGSThreshold.set(thresholdMs);
+ longRunningFGSWithNotification = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ ConstantsObserver.KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING,
+ DeviceConfig::getBoolean,
+ ConstantsObserver.DEFAULT_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING);
+ longRunningFGSWithNotification.set(true);
+
// Long-running FGS with type "location", but ran for a very short time.
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
FOREGROUND_SERVICE_TYPE_LOCATION, 0, null, OP_NONE, null, null,
@@ -1260,6 +1422,7 @@ public final class BackgroundRestrictionTest {
closeIfNotNull(longRunningFGSThreshold);
closeIfNotNull(mediaPlaybackFGSThreshold);
closeIfNotNull(locationFGSThreshold);
+ closeIfNotNull(longRunningFGSWithNotification);
}
}
@@ -1441,6 +1604,7 @@ public final class BackgroundRestrictionTest {
DeviceConfigSession<Boolean> bgPermissionMonitorEnabled = null;
DeviceConfigSession<String> bgPermissionsInMonitor = null;
DeviceConfigSession<Boolean> bgCurrentDrainHighThresholdByBgLocation = null;
+ DeviceConfigSession<Boolean> bgCurrentDrainDecoupleThresholds = null;
mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
@@ -1572,6 +1736,13 @@ public final class BackgroundRestrictionTest {
R.bool.config_bg_current_drain_high_threshold_by_bg_location));
bgCurrentDrainHighThresholdByBgLocation.set(true);
+ bgCurrentDrainDecoupleThresholds = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS,
+ DeviceConfig::getBoolean,
+ AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD);
+ bgCurrentDrainDecoupleThresholds.set(true);
+
mCurrentTimeMillis = 10_000L;
doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
@@ -1990,6 +2161,7 @@ public final class BackgroundRestrictionTest {
closeIfNotNull(bgPermissionMonitorEnabled);
closeIfNotNull(bgPermissionsInMonitor);
closeIfNotNull(bgCurrentDrainHighThresholdByBgLocation);
+ closeIfNotNull(bgCurrentDrainDecoupleThresholds);
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
index 04fe777cd909..b354c7b3d1f3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
@@ -116,14 +116,14 @@ public final class JobConcurrencyManagerTest {
assertFalse(mJobConcurrencyManager.isPkgConcurrencyLimitedLocked(topJob));
// Pending jobs shouldn't affect TOP job's status.
- for (int i = 1; i <= JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; ++i) {
+ for (int i = 1; i <= JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i);
mPendingJobQueue.add(job);
}
assertFalse(mJobConcurrencyManager.isPkgConcurrencyLimitedLocked(topJob));
// Already running jobs shouldn't affect TOP job's status.
- for (int i = 1; i <= JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; ++i) {
+ for (int i = 1; i <= JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE, i);
mJobConcurrencyManager.addRunningJobForTesting(job);
}
@@ -183,9 +183,9 @@ public final class JobConcurrencyManagerTest {
spyOn(testEj);
doReturn(true).when(testEj).shouldTreatAsExpeditedJob();
- setConcurrencyConfig(JobSchedulerService.MAX_JOB_CONTEXTS_COUNT);
+ setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT);
- for (int i = 0; i < JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; ++i) {
+ for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i, i + 1);
mPendingJobQueue.add(job);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt
new file mode 100644
index 000000000000..cf6c82f23730
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm
+
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Binder
+import com.android.server.testutils.any
+import com.android.server.testutils.eq
+import com.android.server.testutils.nullable
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+
+@RunWith(JUnit4::class)
+class DistractingPackageHelperTest : PackageHelperTestBase() {
+
+ lateinit var distractingPackageHelper: DistractingPackageHelper
+
+ override fun setup() {
+ super.setup()
+ distractingPackageHelper = DistractingPackageHelper(
+ pms, rule.mocks().injector, broadcastHelper, suspendPackageHelper)
+ }
+
+ @Test
+ fun setDistractingPackageRestrictionsAsUser() {
+ val unactionedPackages = distractingPackageHelper.setDistractingPackageRestrictionsAsUser(
+ pms.snapshotComputer(), packagesToChange,
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, TEST_USER_ID, deviceOwnerUid)
+ testHandler.flush()
+
+ verify(pms).scheduleWritePackageRestrictions(eq(TEST_USER_ID))
+ verify(broadcastHelper).sendPackageBroadcast(eq(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED),
+ nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
+ nullable(), nullable(), nullable())
+
+ val modifiedPackages = bundleCaptor.value.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST)
+ val distractionFlags = bundleCaptor.value.getInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS)
+ assertThat(modifiedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2)
+ assertThat(distractionFlags).isEqualTo(PackageManager.RESTRICTION_HIDE_NOTIFICATIONS)
+ assertThat(unactionedPackages).isEmpty()
+ }
+
+ @Test
+ fun setDistractingPackageRestrictionsAsUser_setSameDistractionRestrictionTwice() {
+ distractingPackageHelper.setDistractingPackageRestrictionsAsUser(
+ pms.snapshotComputer(), packagesToChange,
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, TEST_USER_ID, deviceOwnerUid)
+ testHandler.flush()
+ clearInvocations(pms)
+ clearInvocations(broadcastHelper)
+
+ val unactionedPackages = distractingPackageHelper.setDistractingPackageRestrictionsAsUser(
+ pms.snapshotComputer(), packagesToChange,
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, TEST_USER_ID, deviceOwnerUid)
+ testHandler.flush()
+ verify(pms, never()).scheduleWritePackageRestrictions(eq(TEST_USER_ID))
+ verify(broadcastHelper, never()).sendPackageBroadcast(
+ eq(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED), nullable(), bundleCaptor.capture(),
+ anyInt(), nullable(), nullable(), any(), nullable(), nullable(), nullable())
+ assertThat(unactionedPackages).isEmpty()
+ }
+
+ @Test
+ fun setDistractingPackageRestrictionsAsUser_emptyPackageName() {
+ var unactionedPackages = distractingPackageHelper.setDistractingPackageRestrictionsAsUser(
+ pms.snapshotComputer(), null /* packageNames */,
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, TEST_USER_ID, deviceOwnerUid)
+ assertThat(unactionedPackages).isNull()
+
+ unactionedPackages = distractingPackageHelper.setDistractingPackageRestrictionsAsUser(
+ pms.snapshotComputer(), arrayOfNulls(0) /* packageNames */,
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, TEST_USER_ID, deviceOwnerUid)
+ assertThat(unactionedPackages).isEmpty()
+ }
+
+ @Test
+ fun setDistractingPackageRestrictionsAsUser_callerIsNotAllowed() {
+ val unactionedPackages = distractingPackageHelper.setDistractingPackageRestrictionsAsUser(
+ pms.snapshotComputer(), arrayOf(TEST_PACKAGE_1),
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, TEST_USER_ID, Binder.getCallingUid())
+
+ assertThat(unactionedPackages).asList().hasSize(1)
+ assertThat(unactionedPackages).asList().contains(TEST_PACKAGE_1)
+ }
+
+ @Test
+ fun setDistractingPackageRestrictionsAsUser_setCallerItself() {
+ val unactionedPackages = distractingPackageHelper.setDistractingPackageRestrictionsAsUser(
+ pms.snapshotComputer(), arrayOf(DEVICE_OWNER_PACKAGE),
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, TEST_USER_ID, Binder.getCallingUid())
+
+ assertThat(unactionedPackages).asList().hasSize(1)
+ assertThat(unactionedPackages).asList().contains(DEVICE_OWNER_PACKAGE)
+ }
+
+ @Test
+ fun setDistractingPackageRestrictionsAsUser_nonexistentPackage() {
+ val unactionedPackages = distractingPackageHelper.setDistractingPackageRestrictionsAsUser(
+ pms.snapshotComputer(), arrayOf(NONEXISTENT_PACKAGE),
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, TEST_USER_ID, deviceOwnerUid)
+
+ assertThat(unactionedPackages).asList().hasSize(1)
+ assertThat(unactionedPackages).asList().contains(NONEXISTENT_PACKAGE)
+ }
+
+ @Test
+ fun setDistractingPackageRestrictionsAsUser_setKnownPackages() {
+ val knownPackages = arrayOf(DEVICE_ADMIN_PACKAGE, DEFAULT_HOME_PACKAGE, DIALER_PACKAGE,
+ INSTALLER_PACKAGE, UNINSTALLER_PACKAGE, VERIFIER_PACKAGE,
+ PERMISSION_CONTROLLER_PACKAGE)
+ val unactionedPackages = distractingPackageHelper.setDistractingPackageRestrictionsAsUser(
+ pms.snapshotComputer(), knownPackages,
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, TEST_USER_ID, deviceOwnerUid)
+
+ assertThat(unactionedPackages.size).isEqualTo(knownPackages.size)
+ for (pkg in knownPackages) {
+ assertThat(unactionedPackages).asList().contains(pkg)
+ }
+ }
+
+ @Test
+ fun removeDistractingPackageRestrictions() {
+ distractingPackageHelper.setDistractingPackageRestrictionsAsUser(
+ pms.snapshotComputer(), packagesToChange,
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, TEST_USER_ID, deviceOwnerUid)
+ testHandler.flush()
+ clearInvocations(pms)
+ clearInvocations(broadcastHelper)
+
+ distractingPackageHelper.removeDistractingPackageRestrictions(pms.snapshotComputer(),
+ packagesToChange, TEST_USER_ID)
+ testHandler.flush()
+
+ verify(pms).scheduleWritePackageRestrictions(eq(TEST_USER_ID))
+ verify(broadcastHelper).sendPackageBroadcast(eq(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED),
+ nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
+ nullable(), nullable(), nullable())
+ val modifiedPackages = bundleCaptor.value.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST)
+ val distractionFlags = bundleCaptor.value.getInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS)
+ assertThat(modifiedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2)
+ assertThat(distractionFlags).isEqualTo(PackageManager.RESTRICTION_NONE)
+ }
+
+ @Test
+ fun removeDistractingPackageRestrictions_notDistractingPackage() {
+ distractingPackageHelper.removeDistractingPackageRestrictions(pms.snapshotComputer(),
+ arrayOf(TEST_PACKAGE_1), TEST_USER_ID)
+ testHandler.flush()
+
+ verify(pms, never()).scheduleWritePackageRestrictions(eq(TEST_USER_ID))
+ verify(broadcastHelper, never()).sendPackageBroadcast(eq(
+ Intent.ACTION_DISTRACTING_PACKAGES_CHANGED), nullable(), nullable(), anyInt(),
+ nullable(), nullable(), any(), nullable(), nullable(), nullable())
+ }
+
+ @Test
+ fun removeDistractingPackageRestrictions_emptyPackageName() {
+ distractingPackageHelper.removeDistractingPackageRestrictions(pms.snapshotComputer(),
+ null /* packagesToChange */, TEST_USER_ID)
+ testHandler.flush()
+ verify(pms, never()).scheduleWritePackageRestrictions(eq(TEST_USER_ID))
+ verify(broadcastHelper, never()).sendPackageBroadcast(eq(
+ Intent.ACTION_DISTRACTING_PACKAGES_CHANGED), nullable(), nullable(), anyInt(),
+ nullable(), nullable(), any(), nullable(), nullable(), nullable())
+
+ distractingPackageHelper.removeDistractingPackageRestrictions(pms.snapshotComputer(),
+ arrayOfNulls(0), TEST_USER_ID)
+ testHandler.flush()
+ verify(pms, never()).scheduleWritePackageRestrictions(eq(TEST_USER_ID))
+ verify(broadcastHelper, never()).sendPackageBroadcast(eq(
+ Intent.ACTION_DISTRACTING_PACKAGES_CHANGED), nullable(), nullable(), anyInt(),
+ nullable(), nullable(), any(), nullable(), nullable(), nullable())
+ }
+} \ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index cb9f003b6e3e..353c8e22cceb 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -194,7 +194,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
val packageParser: PackageParser2 = mock()
val keySetManagerService: KeySetManagerService = mock()
val packageAbiHelper: PackageAbiHelper = mock()
- val appsFilter: AppsFilter = mock {
+ val appsFilter: AppsFilterImpl = mock {
whenever(snapshot()) { this@mock }
}
val dexManager: DexManager = mock()
@@ -203,6 +203,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
val domainVerificationManagerInternal: DomainVerificationManagerInternal = mock()
val handler = TestHandler(null)
val defaultAppProvider: DefaultAppProvider = mock()
+ val backgroundHandler = TestHandler(null)
}
companion object {
@@ -223,6 +224,10 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
DEFAULT_VERSION_INFO.sdkVersion = Build.VERSION_CODES.R
DEFAULT_VERSION_INFO.databaseVersion = Settings.CURRENT_DATABASE_VERSION
}
+
+ fun addDefaultSharedLibrary(libName: String, libEntry: SystemConfig.SharedLibraryEntry) {
+ DEFAULT_SHARED_LIBRARIES_LIST[libName] = libEntry
+ }
}
/**
@@ -282,6 +287,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
.thenReturn(mocks.domainVerificationManagerInternal)
whenever(mocks.injector.handler) { mocks.handler }
whenever(mocks.injector.defaultAppProvider) { mocks.defaultAppProvider }
+ whenever(mocks.injector.backgroundHandler) { mocks.backgroundHandler }
wheneverStatic { SystemConfig.getInstance() }.thenReturn(mocks.systemConfig)
whenever(mocks.systemConfig.availableFeatures).thenReturn(DEFAULT_AVAILABLE_FEATURES_MAP)
whenever(mocks.systemConfig.sharedLibraries).thenReturn(DEFAULT_SHARED_LIBRARIES_LIST)
@@ -365,7 +371,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
})
existingSettingBuilderRef[0]?.setPackage(null)
val packageSetting = existingSettingBuilderRef[0]?.let { withExistingSetting(it) }!!.build()
- addPreExistingSetting(packageName, packageSetting)
+ addPreExistingSetting(packageSetting.name, packageSetting)
}
/**
@@ -394,7 +400,8 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
stageParse(apkPath, pkg)
val parentFile = apkPath.parentFile
val settingBuilder = withSetting(createBasicSettingBuilder(parentFile, pkg))
- stageSettingInsert(packageName, settingBuilder.build())
+ val packageSetting = settingBuilder.build()
+ stageSettingInsert(packageSetting.name, packageSetting)
}
/**
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt
new file mode 100644
index 000000000000..bd012fc7837e
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm
+
+import android.os.Build
+import android.os.Bundle
+import android.os.UserHandle
+import android.os.UserManager
+import com.android.server.pm.pkg.PackageStateInternal
+import com.android.server.testutils.TestHandler
+import com.android.server.testutils.any
+import com.android.server.testutils.eq
+import com.android.server.testutils.whenever
+import org.junit.Before
+import org.junit.Rule
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.spy
+import org.mockito.MockitoAnnotations
+
+open class PackageHelperTestBase {
+
+ companion object {
+ const val TEST_PACKAGE_1 = "com.android.test.package1"
+ const val TEST_PACKAGE_2 = "com.android.test.package2"
+ const val DEVICE_OWNER_PACKAGE = "com.android.test.owner"
+ const val NONEXISTENT_PACKAGE = "com.android.test.nonexistent"
+ const val DEVICE_ADMIN_PACKAGE = "com.android.test.known.device.admin"
+ const val DEFAULT_HOME_PACKAGE = "com.android.test.known.home"
+ const val DIALER_PACKAGE = "com.android.test.known.dialer"
+ const val INSTALLER_PACKAGE = "com.android.test.known.installer"
+ const val UNINSTALLER_PACKAGE = "com.android.test.known.uninstaller"
+ const val VERIFIER_PACKAGE = "com.android.test.known.verifier"
+ const val PERMISSION_CONTROLLER_PACKAGE = "com.android.test.known.permission"
+ const val TEST_USER_ID = 0
+ }
+
+ lateinit var pms: PackageManagerService
+ lateinit var suspendPackageHelper: SuspendPackageHelper
+ lateinit var testHandler: TestHandler
+ lateinit var defaultAppProvider: DefaultAppProvider
+ lateinit var packageSetting1: PackageStateInternal
+ lateinit var packageSetting2: PackageStateInternal
+ lateinit var ownerSetting: PackageStateInternal
+ lateinit var packagesToChange: Array<String>
+ lateinit var uidsToChange: IntArray
+
+ @Mock
+ lateinit var broadcastHelper: BroadcastHelper
+ @Mock
+ lateinit var protectedPackages: ProtectedPackages
+
+ @Captor
+ lateinit var bundleCaptor: ArgumentCaptor<Bundle>
+
+ @Rule
+ @JvmField
+ val rule = MockSystemRule()
+ var deviceOwnerUid = 0
+
+ @Before
+ @Throws(Exception::class)
+ open fun setup() {
+ MockitoAnnotations.initMocks(this)
+ rule.system().stageNominalSystemState()
+ pms = spy(createPackageManagerService(
+ TEST_PACKAGE_1, TEST_PACKAGE_2, DEVICE_OWNER_PACKAGE, DEVICE_ADMIN_PACKAGE,
+ DEFAULT_HOME_PACKAGE, DIALER_PACKAGE, INSTALLER_PACKAGE, UNINSTALLER_PACKAGE,
+ VERIFIER_PACKAGE, PERMISSION_CONTROLLER_PACKAGE))
+ suspendPackageHelper = SuspendPackageHelper(
+ pms, rule.mocks().injector, broadcastHelper, protectedPackages)
+ defaultAppProvider = rule.mocks().defaultAppProvider
+ testHandler = rule.mocks().handler
+ packageSetting1 = pms.snapshotComputer().getPackageStateInternal(TEST_PACKAGE_1)!!
+ packageSetting2 = pms.snapshotComputer().getPackageStateInternal(TEST_PACKAGE_2)!!
+ ownerSetting = pms.snapshotComputer().getPackageStateInternal(DEVICE_OWNER_PACKAGE)!!
+ deviceOwnerUid = UserHandle.getUid(TEST_USER_ID, ownerSetting.appId)
+ packagesToChange = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
+ uidsToChange = intArrayOf(packageSetting1.appId, packageSetting2.appId)
+
+ whenever(protectedPackages.getDeviceOwnerOrProfileOwnerPackage(eq(TEST_USER_ID)))
+ .thenReturn(DEVICE_OWNER_PACKAGE)
+ whenever(rule.mocks().userManagerService.hasUserRestriction(
+ eq(UserManager.DISALLOW_APPS_CONTROL), eq(TEST_USER_ID))).thenReturn(true)
+ whenever(rule.mocks().userManagerService.hasUserRestriction(
+ eq(UserManager.DISALLOW_UNINSTALL_APPS), eq(TEST_USER_ID))).thenReturn(true)
+ mockKnownPackages(pms)
+ }
+
+ private fun mockKnownPackages(pms: PackageManagerService) {
+ Mockito.doAnswer { it.arguments[0] == DEVICE_ADMIN_PACKAGE }.`when`(pms)
+ .isPackageDeviceAdmin(any(), any())
+ Mockito.doReturn(DEFAULT_HOME_PACKAGE).`when`(defaultAppProvider)
+ .getDefaultHome(eq(TEST_USER_ID))
+ Mockito.doReturn(DIALER_PACKAGE).`when`(defaultAppProvider)
+ .getDefaultDialer(eq(TEST_USER_ID))
+ Mockito.doReturn(arrayOf(INSTALLER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal(
+ any(), eq(KnownPackages.PACKAGE_INSTALLER), eq(TEST_USER_ID))
+ Mockito.doReturn(arrayOf(UNINSTALLER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal(
+ any(), eq(KnownPackages.PACKAGE_UNINSTALLER), eq(TEST_USER_ID))
+ Mockito.doReturn(arrayOf(VERIFIER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal(
+ any(), eq(KnownPackages.PACKAGE_VERIFIER), eq(TEST_USER_ID))
+ Mockito.doReturn(arrayOf(PERMISSION_CONTROLLER_PACKAGE)).`when`(pms)
+ .getKnownPackageNamesInternal(any(),
+ eq(KnownPackages.PACKAGE_PERMISSION_CONTROLLER), eq(TEST_USER_ID))
+ }
+
+ private fun createPackageManagerService(vararg stageExistingPackages: String):
+ PackageManagerService {
+ stageExistingPackages.forEach {
+ rule.system().stageScanExistingPackage(it, 1L,
+ rule.system().dataAppDirectory)
+ }
+ var pms = PackageManagerService(rule.mocks().injector,
+ false /* coreOnly */,
+ false /* factoryTest */,
+ MockSystem.DEFAULT_VERSION_INFO.fingerprint,
+ false /* isEngBuild */,
+ false /* isUserDebugBuild */,
+ Build.VERSION_CODES.CUR_DEVELOPMENT,
+ Build.VERSION.INCREMENTAL)
+ rule.system().validateFinalState()
+ return pms
+ }
+} \ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
index 97b52a98b266..bd36322664b5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -41,14 +41,13 @@ import com.android.server.utils.WatchedLongSparseArray
import com.google.common.truth.Truth.assertThat
import libcore.util.HexEncoding
import org.junit.Before
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.rules.TemporaryFolder
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.Mock
-import org.mockito.Mockito.anyLong
-import org.mockito.Mockito.anyString
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -57,7 +56,6 @@ import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertTrue
-@Ignore("b/216603387")
@RunWith(JUnit4::class)
class SharedLibrariesImplTest {
@@ -67,24 +65,27 @@ class SharedLibrariesImplTest {
const val BUILTIN_LIB_NAME = "builtin.lib"
const val STATIC_LIB_NAME = "static.lib"
const val STATIC_LIB_VERSION = 7L
- const val STATIC_LIB_PACKAGE_NAME = "com.android.lib.static.provider"
+ const val STATIC_LIB_DECLARING_PACKAGE_NAME = "com.android.lib.static.provider"
+ const val STATIC_LIB_PACKAGE_NAME = "com.android.lib.static.provider_7"
const val DYNAMIC_LIB_NAME = "dynamic.lib"
const val DYNAMIC_LIB_PACKAGE_NAME = "com.android.lib.dynamic.provider"
const val CONSUMER_PACKAGE_NAME = "com.android.lib.consumer"
const val VERSION_UNDEFINED = SharedLibraryInfo.VERSION_UNDEFINED.toLong()
}
+ private val mMockSystem = MockSystemRule()
+ private val mTempFolder = TemporaryFolder()
+
@Rule
@JvmField
- val mRule = MockSystemRule()
-
- private val mExistingPackages: ArrayMap<String, AndroidPackage> = ArrayMap()
- private val mExistingSettings: MutableMap<String, PackageSetting> = mutableMapOf()
+ val mRules = RuleChain.outerRule(mTempFolder).around(mMockSystem)!!
private lateinit var mSharedLibrariesImpl: SharedLibrariesImpl
private lateinit var mPms: PackageManagerService
private lateinit var mSettings: Settings
private lateinit var mComputer: Computer
+ private lateinit var mExistingPackages: ArrayMap<String, AndroidPackage>
+ private lateinit var builtinLibDirectory: File
@Mock
private lateinit var mDeletePackageHelper: DeletePackageHelper
@@ -98,10 +99,11 @@ class SharedLibrariesImplTest {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- mRule.system().stageNominalSystemState()
- addExistingPackages()
+ mMockSystem.system().stageNominalSystemState()
+ stageBuiltinLibrary(mTempFolder.newFolder())
+ stageScanExistingPackages()
- mPms = spy(PackageManagerService(mRule.mocks().injector,
+ mPms = spy(PackageManagerService(mMockSystem.mocks().injector,
false /*coreOnly*/,
false /*factoryTest*/,
MockSystem.DEFAULT_VERSION_INFO.fingerprint,
@@ -109,28 +111,27 @@ class SharedLibrariesImplTest {
false /*isUserDebugBuild*/,
Build.VERSION_CODES.CUR_DEVELOPMENT,
Build.VERSION.INCREMENTAL))
- mSettings = mRule.mocks().injector.settings
- mSharedLibrariesImpl = SharedLibrariesImpl(mPms, mRule.mocks().injector)
+ mMockSystem.system().validateFinalState()
+ mSettings = mMockSystem.mocks().injector.settings
+ mSharedLibrariesImpl = mMockSystem.mocks().injector.sharedLibrariesImpl
mSharedLibrariesImpl.setDeletePackageHelper(mDeletePackageHelper)
- addExistingSharedLibraries()
-
- mComputer = mock {
- whenever(sharedLibraries) { mSharedLibrariesImpl.sharedLibraries }
- whenever(resolveInternalPackageName(anyString(), anyLong())) { arguments[0] }
- }
+ mComputer = spy(mPms.snapshotComputer())
+ mExistingPackages = getExistingPackages(
+ DYNAMIC_LIB_PACKAGE_NAME, STATIC_LIB_PACKAGE_NAME, CONSUMER_PACKAGE_NAME)
- whenever(mSettings.getPackageLPr(any())) { mExistingSettings[arguments[0]] }
- whenever(mRule.mocks().injector.getSystemService(StorageManager::class.java))
+ whenever(mMockSystem.mocks().injector.getSystemService(StorageManager::class.java))
.thenReturn(mStorageManager)
whenever(mStorageManager.findPathForUuid(nullable())).thenReturn(mFile)
doAnswer { mComputer }.`when`(mPms).snapshotComputer()
+ doAnswer { STATIC_LIB_PACKAGE_NAME }.`when`(mComputer).resolveInternalPackageName(
+ eq(STATIC_LIB_DECLARING_PACKAGE_NAME), eq(STATIC_LIB_VERSION))
whenever(mDeletePackageHelper.deletePackageX(any(), any(), any(), any(), any()))
.thenReturn(PackageManager.DELETE_SUCCEEDED)
- whenever(mRule.mocks().injector.compatibility).thenReturn(mPlatformCompat)
+ whenever(mMockSystem.mocks().injector.compatibility).thenReturn(mPlatformCompat)
wheneverStatic { HexEncoding.decode(STATIC_LIB_NAME, false) }
.thenReturn(PackageUtils.computeSha256DigestBytes(
- mExistingSettings[STATIC_LIB_PACKAGE_NAME]!!
- .pkg.signingDetails.signatures!![0].toByteArray()))
+ mSettings.getPackageLPr(STATIC_LIB_PACKAGE_NAME)
+ .pkg.signingDetails.signatures!![0].toByteArray()))
}
@Test
@@ -183,9 +184,6 @@ class SharedLibrariesImplTest {
@Test
fun removeSharedLibrary() {
- doAnswer { mutableListOf(VersionedPackage(CONSUMER_PACKAGE_NAME, 1L)) }
- .`when`(mComputer)
- .getPackagesUsingSharedLibrary(any(), any(), any(), any())
val staticInfo = mSharedLibrariesImpl
.getSharedLibraryInfo(STATIC_LIB_NAME, STATIC_LIB_VERSION)!!
@@ -194,8 +192,6 @@ class SharedLibrariesImplTest {
assertThat(mSharedLibrariesImpl.getSharedLibraryInfos(STATIC_LIB_NAME)).isNull()
assertThat(mSharedLibrariesImpl
.getStaticLibraryInfos(staticInfo.declaringPackage.packageName)).isNull()
- verify(mExistingSettings[CONSUMER_PACKAGE_NAME]!!)
- .setOverlayPathsForLibrary(any(), nullable(), any())
}
@Test
@@ -209,11 +205,11 @@ class SharedLibrariesImplTest {
@Test
fun getLatestSharedLibraVersion() {
- val newLibSetting = addPackage(STATIC_LIB_PACKAGE_NAME + "_" + 10, 10L,
+ val pair = createBasicAndroidPackage(STATIC_LIB_PACKAGE_NAME + "_" + 10, 10L,
staticLibrary = STATIC_LIB_NAME, staticLibraryVersion = 10L)
val latestInfo =
- mSharedLibrariesImpl.getLatestStaticSharedLibraVersionLPr(newLibSetting.pkg)!!
+ mSharedLibrariesImpl.getLatestStaticSharedLibraVersionLPr(pair.second)!!
assertThat(latestInfo).isNotNull()
assertThat(latestInfo.name).isEqualTo(STATIC_LIB_NAME)
@@ -238,7 +234,8 @@ class SharedLibrariesImplTest {
@Test
fun updateSharedLibraries_withDynamicLibPackage() {
- val testPackageSetting = mExistingSettings[DYNAMIC_LIB_PACKAGE_NAME]!!
+ val testPackageSetting = mSettings.getPackageLPr(DYNAMIC_LIB_PACKAGE_NAME)
+ testPackageSetting.setPkgStateLibraryFiles(listOf())
assertThat(testPackageSetting.usesLibraryFiles).isEmpty()
mSharedLibrariesImpl.updateSharedLibrariesLPw(testPackageSetting.pkg, testPackageSetting,
@@ -250,52 +247,60 @@ class SharedLibrariesImplTest {
@Test
fun updateSharedLibraries_withStaticLibPackage() {
- val testPackageSetting = mExistingSettings[STATIC_LIB_PACKAGE_NAME]!!
+ val testPackageSetting = mSettings.getPackageLPr(STATIC_LIB_PACKAGE_NAME)
+ testPackageSetting.setPkgStateLibraryFiles(listOf())
assertThat(testPackageSetting.usesLibraryFiles).isEmpty()
mSharedLibrariesImpl.updateSharedLibrariesLPw(testPackageSetting.pkg, testPackageSetting,
null /* changingLib */, null /* changingLibSetting */, mExistingPackages)
- assertThat(testPackageSetting.usesLibraryFiles).hasSize(1)
+ assertThat(testPackageSetting.usesLibraryFiles).hasSize(2)
+ assertThat(testPackageSetting.usesLibraryFiles).contains(builtinLibPath(BUILTIN_LIB_NAME))
assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(DYNAMIC_LIB_PACKAGE_NAME))
}
@Test
fun updateSharedLibraries_withConsumerPackage() {
- val testPackageSetting = mExistingSettings[CONSUMER_PACKAGE_NAME]!!
+ val testPackageSetting = mSettings.getPackageLPr(CONSUMER_PACKAGE_NAME)
+ testPackageSetting.setPkgStateLibraryFiles(listOf())
assertThat(testPackageSetting.usesLibraryFiles).isEmpty()
mSharedLibrariesImpl.updateSharedLibrariesLPw(testPackageSetting.pkg, testPackageSetting,
null /* changingLib */, null /* changingLibSetting */, mExistingPackages)
- assertThat(testPackageSetting.usesLibraryFiles).hasSize(2)
+ assertThat(testPackageSetting.usesLibraryFiles).hasSize(3)
+ assertThat(testPackageSetting.usesLibraryFiles).contains(builtinLibPath(BUILTIN_LIB_NAME))
assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(DYNAMIC_LIB_PACKAGE_NAME))
- assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(STATIC_LIB_PACKAGE_NAME))
+ assertThat(testPackageSetting.usesLibraryFiles)
+ .contains(apkPath(STATIC_LIB_DECLARING_PACKAGE_NAME))
}
@Test
fun updateAllSharedLibraries() {
- mExistingSettings.forEach {
- assertThat(it.value.usesLibraryFiles).isEmpty()
+ mExistingPackages.forEach {
+ val setting = mSettings.getPackageLPr(it.key)
+ setting.setPkgStateLibraryFiles(listOf())
+ assertThat(setting.usesLibraryFiles).isEmpty()
}
mSharedLibrariesImpl.updateAllSharedLibrariesLPw(
null /* updatedPkg */, null /* updatedPkgSetting */, mExistingPackages)
- var testPackageSetting = mExistingSettings[DYNAMIC_LIB_PACKAGE_NAME]!!
+ var testPackageSetting = mSettings.getPackageLPr(DYNAMIC_LIB_PACKAGE_NAME)
assertThat(testPackageSetting.usesLibraryFiles).hasSize(1)
assertThat(testPackageSetting.usesLibraryFiles).contains(builtinLibPath(BUILTIN_LIB_NAME))
- testPackageSetting = mExistingSettings[STATIC_LIB_PACKAGE_NAME]!!
+ testPackageSetting = mSettings.getPackageLPr(STATIC_LIB_PACKAGE_NAME)
assertThat(testPackageSetting.usesLibraryFiles).hasSize(2)
assertThat(testPackageSetting.usesLibraryFiles).contains(builtinLibPath(BUILTIN_LIB_NAME))
assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(DYNAMIC_LIB_PACKAGE_NAME))
- testPackageSetting = mExistingSettings[CONSUMER_PACKAGE_NAME]!!
+ testPackageSetting = mSettings.getPackageLPr(CONSUMER_PACKAGE_NAME)
assertThat(testPackageSetting.usesLibraryFiles).hasSize(3)
assertThat(testPackageSetting.usesLibraryFiles).contains(builtinLibPath(BUILTIN_LIB_NAME))
assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(DYNAMIC_LIB_PACKAGE_NAME))
- assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(STATIC_LIB_PACKAGE_NAME))
+ assertThat(testPackageSetting.usesLibraryFiles)
+ .contains(apkPath(STATIC_LIB_DECLARING_PACKAGE_NAME))
}
@Test
@@ -318,7 +323,7 @@ class SharedLibrariesImplTest {
val parsedPackage = pair.second.apply {
isSystem = true
} as ParsedPackage
- val packageSetting = mRule.system()
+ val packageSetting = mMockSystem.system()
.createBasicSettingBuilder(pair.first.parentFile, parsedPackage.hideAsFinal())
.setPkgFlags(ApplicationInfo.FLAG_SYSTEM).build()
val scanRequest = ScanRequest(parsedPackage, null, null, null, null,
@@ -332,54 +337,79 @@ class SharedLibrariesImplTest {
assertThat(allowedInfos[0].name).isEqualTo(TEST_LIB_NAME)
}
- private fun addExistingPackages() {
+ private fun getExistingPackages(vararg args: String): ArrayMap<String, AndroidPackage> {
+ val existingPackages = ArrayMap<String, AndroidPackage>()
+ args.forEach {
+ existingPackages[it] = mSettings.getPackageLPr(it).pkg
+ }
+ return existingPackages
+ }
+
+ private fun stageBuiltinLibrary(folder: File) {
+ builtinLibDirectory = folder
+ val libPath = File(builtinLibPath(BUILTIN_LIB_NAME))
+ libPath.createNewFile()
+ MockSystem.addDefaultSharedLibrary(BUILTIN_LIB_NAME, libEntry(BUILTIN_LIB_NAME))
+ }
+
+ private fun stageScanExistingPackages() {
// add a dynamic shared library that is using the builtin library
- addPackage(DYNAMIC_LIB_PACKAGE_NAME, 1L,
+ stageScanExistingPackage(DYNAMIC_LIB_PACKAGE_NAME, 1L,
libraries = arrayOf(DYNAMIC_LIB_NAME),
usesLibraries = arrayOf(BUILTIN_LIB_NAME))
// add a static shared library v7 that is using the dynamic shared library
- addPackage(STATIC_LIB_PACKAGE_NAME, STATIC_LIB_VERSION,
+ stageScanExistingPackage(STATIC_LIB_DECLARING_PACKAGE_NAME, STATIC_LIB_VERSION,
staticLibrary = STATIC_LIB_NAME, staticLibraryVersion = STATIC_LIB_VERSION,
usesLibraries = arrayOf(DYNAMIC_LIB_NAME))
// add a consumer package that is using the dynamic and static shared library
- addPackage(CONSUMER_PACKAGE_NAME, 1L,
+ stageScanExistingPackage(CONSUMER_PACKAGE_NAME, 1L,
+ isSystem = true,
usesLibraries = arrayOf(DYNAMIC_LIB_NAME),
usesStaticLibraries = arrayOf(STATIC_LIB_NAME),
usesStaticLibraryVersions = arrayOf(STATIC_LIB_VERSION))
}
- private fun addExistingSharedLibraries() {
- mSharedLibrariesImpl.addBuiltInSharedLibraryLPw(libEntry(BUILTIN_LIB_NAME))
- mSharedLibrariesImpl.commitSharedLibraryInfoLPw(
- libOfDynamic(DYNAMIC_LIB_PACKAGE_NAME, DYNAMIC_LIB_NAME))
- mSharedLibrariesImpl.commitSharedLibraryInfoLPw(
- libOfStatic(STATIC_LIB_PACKAGE_NAME, STATIC_LIB_NAME, STATIC_LIB_VERSION))
- }
-
- private fun addPackage(
+ private fun stageScanExistingPackage(
packageName: String,
version: Long,
+ isSystem: Boolean = false,
libraries: Array<String>? = null,
staticLibrary: String? = null,
staticLibraryVersion: Long = 0L,
usesLibraries: Array<String>? = null,
usesStaticLibraries: Array<String>? = null,
usesStaticLibraryVersions: Array<Long>? = null
- ): PackageSetting {
- val pair = createBasicAndroidPackage(packageName, version, libraries, staticLibrary,
- staticLibraryVersion, usesLibraries, usesStaticLibraries, usesStaticLibraryVersions)
- val apkPath = pair.first
- val parsingPackage = pair.second
- val spyPkg = spy((parsingPackage as ParsedPackage).hideAsFinal())
- mExistingPackages[packageName] = spyPkg
-
- val spyPackageSetting = spy(mRule.system()
- .createBasicSettingBuilder(apkPath.parentFile, spyPkg).build())
- mExistingSettings[spyPackageSetting.packageName] = spyPackageSetting
-
- return spyPackageSetting
+ ) {
+ val withPackage = { pkg: PackageImpl ->
+ pkg.setSystem(isSystem || libraries != null)
+ pkg.setTargetSdkVersion(Build.VERSION_CODES.S)
+ libraries?.forEach { pkg.addLibraryName(it) }
+ staticLibrary?.let {
+ pkg.setStaticSharedLibName(it)
+ pkg.setStaticSharedLibVersion(staticLibraryVersion)
+ pkg.setStaticSharedLibrary(true)
+ }
+ usesLibraries?.forEach { pkg.addUsesLibrary(it) }
+ usesStaticLibraries?.forEachIndexed { index, s ->
+ pkg.addUsesStaticLibrary(s,
+ usesStaticLibraryVersions?.get(index) ?: 0L,
+ arrayOf(s))
+ }
+ pkg
+ }
+ val withSetting = { settingBuilder: PackageSettingBuilder ->
+ if (staticLibrary != null) {
+ settingBuilder.setName(getStaticSharedLibInternalPackageName(packageName, version))
+ }
+ if (isSystem || libraries != null) {
+ settingBuilder.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+ }
+ settingBuilder
+ }
+ mMockSystem.system().stageScanExistingPackage(
+ packageName, version, mMockSystem.system().dataAppDirectory, withPackage, withSetting)
}
private fun createBasicAndroidPackage(
@@ -395,8 +425,8 @@ class SharedLibrariesImplTest {
assertFalse { libraries != null && staticLibrary != null }
assertTrue { (usesStaticLibraries?.size ?: -1) == (usesStaticLibraryVersions?.size ?: -1) }
- val pair = mRule.system()
- .createBasicAndroidPackage(mRule.system().dataAppDirectory, packageName, version)
+ val pair = mMockSystem.system()
+ .createBasicAndroidPackage(mMockSystem.system().dataAppDirectory, packageName, version)
pair.second.apply {
setTargetSdkVersion(Build.VERSION_CODES.S)
libraries?.forEach { addLibraryName(it) }
@@ -432,17 +462,17 @@ class SharedLibrariesImplTest {
false /* isNative */)
private fun libOfStatic(
- packageName: String,
+ declaringPackageName: String,
libName: String,
version: Long
): SharedLibraryInfo =
SharedLibraryInfo(null /* path */,
- packageName,
- listOf(apkPath(packageName)),
+ getStaticSharedLibInternalPackageName(declaringPackageName, version),
+ listOf(apkPath(declaringPackageName)),
libName,
version,
SharedLibraryInfo.TYPE_STATIC,
- VersionedPackage(packageName, version /* versionCode */),
+ VersionedPackage(declaringPackageName, version /* versionCode */),
null /* dependentPackages */,
null /* dependencies */,
false /* isNative */)
@@ -459,8 +489,14 @@ class SharedLibrariesImplTest {
null /* dependencies */,
false /* isNative */)
- private fun builtinLibPath(libName: String): String = "/system/app/$libName/$libName.jar"
+ private fun builtinLibPath(libName: String) =
+ File(builtinLibDirectory, "$libName.jar").path
- private fun apkPath(packageName: String): String =
- File(mRule.system().dataAppDirectory, packageName).path
+ private fun apkPath(packageName: String) =
+ File(mMockSystem.system().dataAppDirectory, packageName).path
+
+ private fun getStaticSharedLibInternalPackageName(
+ declaringPackageName: String,
+ version: Long
+ ) = "${declaringPackageName}_$version"
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
index 4818573e9ae5..3ba9ca591fb3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
@@ -17,108 +17,27 @@
package com.android.server.pm
import android.content.Intent
-import android.content.pm.PackageManagerInternal
import android.content.pm.SuspendDialogInfo
import android.os.Binder
-import android.os.Build
-import android.os.Bundle
import android.os.PersistableBundle
-import android.os.UserHandle
-import android.os.UserManager
import android.util.ArrayMap
import android.util.SparseArray
import com.android.server.pm.pkg.PackageStateInternal
-import com.android.server.testutils.TestHandler
import com.android.server.testutils.any
import com.android.server.testutils.eq
import com.android.server.testutils.nullable
import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.Captor
-import org.mockito.Mock
-import org.mockito.Mockito
import org.mockito.Mockito.argThat
-import org.mockito.Mockito.spy
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
@RunWith(JUnit4::class)
-class SuspendPackageHelperTest {
-
- companion object {
- const val TEST_PACKAGE_1 = "com.android.test.package1"
- const val TEST_PACKAGE_2 = "com.android.test.package2"
- const val DEVICE_OWNER_PACKAGE = "com.android.test.owner"
- const val NONEXISTENT_PACKAGE = "com.android.test.nonexistent"
- const val DEVICE_ADMIN_PACKAGE = "com.android.test.known.device.admin"
- const val DEFAULT_HOME_PACKAGE = "com.android.test.known.home"
- const val DIALER_PACKAGE = "com.android.test.known.dialer"
- const val INSTALLER_PACKAGE = "com.android.test.known.installer"
- const val UNINSTALLER_PACKAGE = "com.android.test.known.uninstaller"
- const val VERIFIER_PACKAGE = "com.android.test.known.verifier"
- const val PERMISSION_CONTROLLER_PACKAGE = "com.android.test.known.permission"
- const val TEST_USER_ID = 0
- }
-
- lateinit var pms: PackageManagerService
- lateinit var suspendPackageHelper: SuspendPackageHelper
- lateinit var testHandler: TestHandler
- lateinit var defaultAppProvider: DefaultAppProvider
- lateinit var packageSetting1: PackageStateInternal
- lateinit var packageSetting2: PackageStateInternal
- lateinit var ownerSetting: PackageStateInternal
- lateinit var packagesToSuspend: Array<String>
- lateinit var uidsToSuspend: IntArray
-
- @Mock
- lateinit var broadcastHelper: BroadcastHelper
- @Mock
- lateinit var protectedPackages: ProtectedPackages
-
- @Captor
- lateinit var bundleCaptor: ArgumentCaptor<Bundle>
-
- @Rule
- @JvmField
- val rule = MockSystemRule()
- var deviceOwnerUid = 0
-
- @Before
- @Throws(Exception::class)
- fun setup() {
- MockitoAnnotations.initMocks(this)
- rule.system().stageNominalSystemState()
- pms = spy(createPackageManagerService(
- TEST_PACKAGE_1, TEST_PACKAGE_2, DEVICE_OWNER_PACKAGE, DEVICE_ADMIN_PACKAGE,
- DEFAULT_HOME_PACKAGE, DIALER_PACKAGE, INSTALLER_PACKAGE, UNINSTALLER_PACKAGE,
- VERIFIER_PACKAGE, PERMISSION_CONTROLLER_PACKAGE))
- suspendPackageHelper = SuspendPackageHelper(
- pms, rule.mocks().injector, broadcastHelper, protectedPackages)
- defaultAppProvider = rule.mocks().defaultAppProvider
- testHandler = rule.mocks().handler
- packageSetting1 = pms.snapshotComputer().getPackageStateInternal(TEST_PACKAGE_1)!!
- packageSetting2 = pms.snapshotComputer().getPackageStateInternal(TEST_PACKAGE_2)!!
- ownerSetting = pms.snapshotComputer().getPackageStateInternal(DEVICE_OWNER_PACKAGE)!!
- deviceOwnerUid = UserHandle.getUid(TEST_USER_ID, ownerSetting.appId)
- packagesToSuspend = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
- uidsToSuspend = intArrayOf(packageSetting1.appId, packageSetting2.appId)
-
- whenever(protectedPackages.getDeviceOwnerOrProfileOwnerPackage(eq(TEST_USER_ID)))
- .thenReturn(DEVICE_OWNER_PACKAGE)
- whenever(rule.mocks().userManagerService.hasUserRestriction(
- eq(UserManager.DISALLOW_APPS_CONTROL), eq(TEST_USER_ID))).thenReturn(true)
- whenever(rule.mocks().userManagerService.hasUserRestriction(
- eq(UserManager.DISALLOW_UNINSTALL_APPS), eq(TEST_USER_ID))).thenReturn(true)
- mockKnownPackages(pms)
- }
+class SuspendPackageHelperTest : PackageHelperTestBase() {
@Test
fun setPackagesSuspended() {
@@ -388,7 +307,7 @@ class SuspendPackageHelperTest {
mockAllowList(packageSetting2, allowList(10001, 10002, 10003))
suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
- Intent.ACTION_PACKAGES_SUSPENDED, packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+ Intent.ACTION_PACKAGES_SUSPENDED, packagesToChange, uidsToChange, TEST_USER_ID)
testHandler.flush()
verify(broadcastHelper).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
anyInt(), nullable(), nullable(), any(), nullable(), any(), nullable())
@@ -407,7 +326,7 @@ class SuspendPackageHelperTest {
mockAllowList(packageSetting2, allowList(10001, 10002, 10007))
suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
- Intent.ACTION_PACKAGES_SUSPENDED, packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+ Intent.ACTION_PACKAGES_SUSPENDED, packagesToChange, uidsToChange, TEST_USER_ID)
testHandler.flush()
verify(broadcastHelper, times(2)).sendPackageBroadcast(
any(), nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
@@ -430,7 +349,7 @@ class SuspendPackageHelperTest {
mockAllowList(packageSetting2, null)
suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
- Intent.ACTION_PACKAGES_SUSPENDED, packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+ Intent.ACTION_PACKAGES_SUSPENDED, packagesToChange, uidsToChange, TEST_USER_ID)
testHandler.flush()
verify(broadcastHelper, times(2)).sendPackageBroadcast(
any(), nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
@@ -450,7 +369,7 @@ class SuspendPackageHelperTest {
@Throws(Exception::class)
fun sendPackagesSuspendModifiedForUser() {
suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
- Intent.ACTION_PACKAGES_SUSPENSION_CHANGED, packagesToSuspend, uidsToSuspend,
+ Intent.ACTION_PACKAGES_SUSPENSION_CHANGED, packagesToChange, uidsToChange,
TEST_USER_ID)
testHandler.flush()
verify(broadcastHelper).sendPackageBroadcast(
@@ -475,40 +394,4 @@ class SuspendPackageHelperTest {
))
.thenReturn(list)
}
-
- private fun mockKnownPackages(pms: PackageManagerService) {
- Mockito.doAnswer { it.arguments[0] == DEVICE_ADMIN_PACKAGE }.`when`(pms)
- .isPackageDeviceAdmin(any(), any())
- Mockito.doReturn(DEFAULT_HOME_PACKAGE).`when`(defaultAppProvider)
- .getDefaultHome(eq(TEST_USER_ID))
- Mockito.doReturn(DIALER_PACKAGE).`when`(defaultAppProvider)
- .getDefaultDialer(eq(TEST_USER_ID))
- Mockito.doReturn(arrayOf(INSTALLER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal(
- any(), eq(PackageManagerInternal.PACKAGE_INSTALLER), eq(TEST_USER_ID))
- Mockito.doReturn(arrayOf(UNINSTALLER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal(
- any(), eq(PackageManagerInternal.PACKAGE_UNINSTALLER), eq(TEST_USER_ID))
- Mockito.doReturn(arrayOf(VERIFIER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal(
- any(), eq(PackageManagerInternal.PACKAGE_VERIFIER), eq(TEST_USER_ID))
- Mockito.doReturn(arrayOf(PERMISSION_CONTROLLER_PACKAGE)).`when`(pms)
- .getKnownPackageNamesInternal(any(),
- eq(PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER), eq(TEST_USER_ID))
- }
-
- private fun createPackageManagerService(vararg stageExistingPackages: String):
- PackageManagerService {
- stageExistingPackages.forEach {
- rule.system().stageScanExistingPackage(it, 1L,
- rule.system().dataAppDirectory)
- }
- var pms = PackageManagerService(rule.mocks().injector,
- false /*coreOnly*/,
- false /*factoryTest*/,
- MockSystem.DEFAULT_VERSION_INFO.fingerprint,
- false /*isEngBuild*/,
- false /*isUserDebugBuild*/,
- Build.VERSION_CODES.CUR_DEVELOPMENT,
- Build.VERSION.INCREMENTAL)
- rule.system().validateFinalState()
- return pms
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/appwidget/OWNERS b/services/tests/servicestests/src/com/android/server/appwidget/OWNERS
new file mode 100644
index 000000000000..d724cac4aa3e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appwidget/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/appwidget/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 7b921ababf36..c96b4d66f293 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -40,7 +40,8 @@ import android.app.admin.DevicePolicyManager;
import android.companion.AssociationInfo;
import android.companion.virtual.IVirtualDeviceActivityListener;
import android.companion.virtual.VirtualDeviceParams;
-import android.companion.virtual.audio.IAudioSessionCallback;
+import android.companion.virtual.audio.IAudioConfigChangedCallback;
+import android.companion.virtual.audio.IAudioRoutingCallback;
import android.content.Context;
import android.content.ContextWrapper;
import android.graphics.Point;
@@ -115,7 +116,9 @@ public class VirtualDeviceManagerServiceTest {
IThermalService mIThermalServiceMock;
private PowerManager mPowerManager;
@Mock
- private IAudioSessionCallback mCallback;
+ private IAudioRoutingCallback mRoutingCallback;
+ @Mock
+ private IAudioConfigChangedCallback mConfigChangedCallback;
@Before
public void setUp() {
@@ -258,7 +261,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void onAudioSessionStarting_noDisplay_failsSecurityException() {
assertThrows(SecurityException.class,
- () -> mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mCallback));
+ () -> mDeviceImpl.onAudioSessionStarting(
+ DISPLAY_ID, mRoutingCallback, mConfigChangedCallback));
}
@Test
@@ -300,7 +304,8 @@ public class VirtualDeviceManagerServiceTest {
doCallRealMethod().when(mContext).enforceCallingOrSelfPermission(
eq(Manifest.permission.CREATE_VIRTUAL_DEVICE), anyString());
assertThrows(SecurityException.class,
- () -> mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mCallback));
+ () -> mDeviceImpl.onAudioSessionStarting(
+ DISPLAY_ID, mRoutingCallback, mConfigChangedCallback));
}
@Test
@@ -347,7 +352,7 @@ public class VirtualDeviceManagerServiceTest {
public void onAudioSessionStarting_hasVirtualAudioController() {
mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
- mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mCallback);
+ mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback);
assertThat(mDeviceImpl.getVirtualAudioControllerForTesting()).isNotNull();
}
@@ -355,7 +360,7 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void onAudioSessionEnded_noVirtualAudioController() {
mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
- mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mCallback);
+ mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback);
mDeviceImpl.onAudioSessionEnded();
@@ -365,7 +370,7 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void close_cleanVirtualAudioController() {
mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
- mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mCallback);
+ mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback);
mDeviceImpl.close();
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index f0c907d49a46..75faf4554147 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -26,7 +26,8 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.companion.virtual.VirtualDeviceParams;
-import android.companion.virtual.audio.IAudioSessionCallback;
+import android.companion.virtual.audio.IAudioConfigChangedCallback;
+import android.companion.virtual.audio.IAudioRoutingCallback;
import android.content.Context;
import android.content.ContextWrapper;
import android.media.AudioPlaybackConfiguration;
@@ -60,7 +61,10 @@ public class VirtualAudioControllerTest {
private Context mContext;
private VirtualAudioController mVirtualAudioController;
private GenericWindowPolicyController mGenericWindowPolicyController;
- @Mock IAudioSessionCallback mCallback;
+ @Mock
+ private IAudioRoutingCallback mRoutingCallback;
+ @Mock
+ private IAudioConfigChangedCallback mConfigChangedCallback;
@Before
public void setUp() {
@@ -82,42 +86,46 @@ public class VirtualAudioControllerTest {
public void startListening_receivesCallback() throws RemoteException {
ArraySet<Integer> runningUids = new ArraySet<>();
runningUids.add(APP1_UID);
- int[] appUids = new int[] {APP1_UID};
+ int[] appUids = new int[]{APP1_UID};
- mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback);
+ mVirtualAudioController.startListening(
+ mGenericWindowPolicyController, mRoutingCallback, mConfigChangedCallback);
mGenericWindowPolicyController.onRunningAppsChanged(runningUids);
- verify(mCallback).onAppsNeedingAudioRoutingChanged(appUids);
+ verify(mRoutingCallback).onAppsNeedingAudioRoutingChanged(appUids);
}
@Test
public void stopListening_removesCallback() throws RemoteException {
ArraySet<Integer> runningUids = new ArraySet<>();
runningUids.add(APP1_UID);
- int[] appUids = new int[] {APP1_UID};
- mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback);
+ int[] appUids = new int[]{APP1_UID};
+ mVirtualAudioController.startListening(
+ mGenericWindowPolicyController, mRoutingCallback, mConfigChangedCallback);
mVirtualAudioController.stopListening();
mGenericWindowPolicyController.onRunningAppsChanged(runningUids);
- verify(mCallback, never()).onAppsNeedingAudioRoutingChanged(appUids);
+ verify(mRoutingCallback, never()).onAppsNeedingAudioRoutingChanged(appUids);
}
@Test
public void onRunningAppsChanged_notifiesAudioRoutingModified() throws RemoteException {
- mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback);
+ mVirtualAudioController.startListening(
+ mGenericWindowPolicyController, mRoutingCallback, mConfigChangedCallback);
ArraySet<Integer> runningUids = new ArraySet<>();
runningUids.add(APP1_UID);
mVirtualAudioController.onRunningAppsChanged(runningUids);
- int[] appUids = new int[] {APP1_UID};
- verify(mCallback).onAppsNeedingAudioRoutingChanged(appUids);
+ int[] appUids = new int[]{APP1_UID};
+ verify(mRoutingCallback).onAppsNeedingAudioRoutingChanged(appUids);
}
@Test
public void onRunningAppsChanged_audioIsPlaying_doesNothing() throws RemoteException {
- mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback);
+ mVirtualAudioController.startListening(
+ mGenericWindowPolicyController, mRoutingCallback, mConfigChangedCallback);
mVirtualAudioController.addPlayingAppsForTesting(APP2_UID);
ArraySet<Integer> runningUids = new ArraySet<>();
@@ -125,7 +133,7 @@ public class VirtualAudioControllerTest {
mVirtualAudioController.onRunningAppsChanged(runningUids);
int[] appUids = new int[]{APP1_UID};
- verify(mCallback, never()).onAppsNeedingAudioRoutingChanged(appUids);
+ verify(mRoutingCallback, never()).onAppsNeedingAudioRoutingChanged(appUids);
}
@Test
@@ -145,7 +153,8 @@ public class VirtualAudioControllerTest {
@Test
public void onPlaybackConfigChanged_sendsCallback() throws RemoteException {
- mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback);
+ mVirtualAudioController.startListening(
+ mGenericWindowPolicyController, mRoutingCallback, mConfigChangedCallback);
ArraySet<Integer> runningUids = new ArraySet<>();
runningUids.add(APP1_UID);
mVirtualAudioController.onRunningAppsChanged(runningUids);
@@ -153,12 +162,13 @@ public class VirtualAudioControllerTest {
mVirtualAudioController.onPlaybackConfigChanged(configs);
- verify(mCallback).onPlaybackConfigChanged(configs);
+ verify(mConfigChangedCallback).onPlaybackConfigChanged(configs);
}
@Test
public void onRecordingConfigChanged_sendsCallback() throws RemoteException {
- mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback);
+ mVirtualAudioController.startListening(
+ mGenericWindowPolicyController, mRoutingCallback, mConfigChangedCallback);
ArraySet<Integer> runningUids = new ArraySet<>();
runningUids.add(APP1_UID);
mVirtualAudioController.onRunningAppsChanged(runningUids);
@@ -166,7 +176,7 @@ public class VirtualAudioControllerTest {
mVirtualAudioController.onRecordingConfigChanged(configs);
- verify(mCallback).onRecordingConfigChanged(configs);
+ verify(mConfigChangedCallback).onRecordingConfigChanged(configs);
}
private List<AudioPlaybackConfiguration> createPlaybackConfigurations(
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index a2b1c1cb1a49..f834b3438aa3 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -40,6 +40,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
+import android.os.IpcDataCache;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
@@ -75,6 +76,10 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
@Before
public void setUp() throws Exception {
+ // Disable caches in this test process. This must happen early, since some of the
+ // following initialization steps invalidate caches.
+ IpcDataCache.disableForTestMode();
+
mContext = getContext();
// Make createContextAsUser to work.
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 197c21fad74a..ea136da5f323 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -48,6 +48,9 @@ import static android.app.admin.DevicePolicyManager.WIFI_SECURITY_PERSONAL;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.PasswordMetrics.computeForPasswordOrPin;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
+import static android.location.LocationManager.FUSED_PROVIDER;
+import static android.location.LocationManager.GPS_PROVIDER;
+import static android.location.LocationManager.NETWORK_PROVIDER;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK;
@@ -125,6 +128,7 @@ import android.net.wifi.WifiSsid;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
+import android.os.IpcDataCache;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
@@ -258,6 +262,10 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Before
public void setUp() throws Exception {
+ // Disable caches in this test process. This must happen early, since some of the
+ // following initialization steps invalidate caches.
+ IpcDataCache.disableForTestMode();
+
mContext = getContext();
mServiceContext = mContext;
mServiceContext.binder.callingUid = DpmMockContext.CALLER_UID;
@@ -8462,34 +8470,44 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSendLostModeLocationUpdate_asDeviceOwner() throws Exception {
- final String TEST_PROVIDER = "network";
mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE);
setDeviceOwner();
- when(getServices().locationManager.getAllProviders()).thenReturn(List.of(TEST_PROVIDER));
- when(getServices().locationManager.isProviderEnabled(TEST_PROVIDER)).thenReturn(true);
+ when(getServices().locationManager.isProviderEnabled(FUSED_PROVIDER)).thenReturn(true);
dpm.sendLostModeLocationUpdate(getServices().executor, /* empty callback */ result -> {});
verify(getServices().locationManager, times(1)).getCurrentLocation(
- eq(TEST_PROVIDER), any(), eq(getServices().executor), any());
+ eq(FUSED_PROVIDER), any(), eq(getServices().executor), any());
}
@Test
public void testSendLostModeLocationUpdate_asProfileOwnerOfOrgOwnedDevice() throws Exception {
- final String TEST_PROVIDER = "network";
final int MANAGED_PROFILE_ADMIN_UID =
UserHandle.getUid(CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID);
mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE);
addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
- when(getServices().locationManager.getAllProviders()).thenReturn(List.of(TEST_PROVIDER));
- when(getServices().locationManager.isProviderEnabled(TEST_PROVIDER)).thenReturn(true);
+ when(getServices().locationManager.isProviderEnabled(FUSED_PROVIDER)).thenReturn(true);
dpm.sendLostModeLocationUpdate(getServices().executor, /* empty callback */ result -> {});
verify(getServices().locationManager, times(1)).getCurrentLocation(
- eq(TEST_PROVIDER), any(), eq(getServices().executor), any());
+ eq(FUSED_PROVIDER), any(), eq(getServices().executor), any());
+ }
+
+ @Test
+ public void testSendLostModeLocationUpdate_noProviderIsEnabled() throws Exception {
+ mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE);
+ setDeviceOwner();
+ when(getServices().locationManager.isProviderEnabled(FUSED_PROVIDER)).thenReturn(false);
+ when(getServices().locationManager.isProviderEnabled(NETWORK_PROVIDER)).thenReturn(false);
+ when(getServices().locationManager.isProviderEnabled(GPS_PROVIDER)).thenReturn(false);
+
+ dpm.sendLostModeLocationUpdate(getServices().executor, /* empty callback */ result -> {});
+
+ verify(getServices().locationManager, never()).getCurrentLocation(
+ eq(FUSED_PROVIDER), any(), eq(getServices().executor), any());
}
private void setupVpnAuthorization(String userVpnPackage, int userVpnUid) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java
index 743b25f5c2b4..69aaf010d0e0 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java
@@ -32,6 +32,7 @@ import android.app.admin.DnsEvent;
import android.app.admin.NetworkEvent;
import android.content.Intent;
import android.os.Bundle;
+import android.os.IpcDataCache;
import android.os.Message;
import android.os.Parcel;
import android.os.SystemClock;
@@ -56,6 +57,10 @@ public class NetworkEventTest extends DpmTestBase {
@Before
public void setUp() throws Exception {
+ // Disable caches in this test process. This must happen early, since some of the
+ // following initialization steps invalidate caches.
+ IpcDataCache.disableForTestMode();
+
mSpiedDpmMockContext = spy(mMockContext);
mSpiedDpmMockContext.callerPermissions.add(
android.Manifest.permission.MANAGE_DEVICE_ADMINS);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
index 9a5254d3e00d..d1706f857c13 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
@@ -24,6 +24,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import android.content.ComponentName;
+import android.os.IpcDataCache;
import android.os.UserHandle;
import android.test.suitebuilder.annotation.SmallTest;
@@ -33,6 +34,7 @@ import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.Owners
import com.google.android.collect.Lists;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,6 +55,13 @@ public class OwnersTest extends DpmTestBase {
private static final List<String> DEVICE_OWNER_PROTECTED_PACKAGES =
Lists.newArrayList("package_1", "package_2");
+ @Before
+ public void setUp() throws Exception {
+ // Disable caches in this test process. This must happen early, since some of the
+ // following initialization steps invalidate caches.
+ IpcDataCache.disableForTestMode();
+ }
+
@Test
public void testUpgrade01() throws Exception {
getServices().addUsers(10, 11, 20, 21);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
index b41a5311c89f..834a514b978a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
@@ -28,6 +28,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.os.IpcDataCache;
import android.os.Parcel;
import android.os.UserHandle;
import android.util.TypedXmlPullParser;
@@ -128,6 +129,10 @@ public class PolicyVersionUpgraderTest extends DpmTestBase {
@Before
public void setUp() {
+ // Disable caches in this test process. This must happen early, since some of the
+ // following initialization steps invalidate caches.
+ IpcDataCache.disableForTestMode();
+
mProvider = new FakePolicyUpgraderDataProvider();
mUpgrader = new PolicyVersionUpgrader(mProvider);
mDataDir = new File(mRealTestContext.getCacheDir(), "test-data");
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 6fc3354f07e7..86130daf4aac 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -2033,4 +2033,32 @@ public class HdmiCecLocalDevicePlaybackTest {
mTestLooper.dispatchAll();
assertThat(mPowerManager.isInteractive()).isFalse();
}
+
+ @Test
+ public void onHotplugClearsDevices() {
+ mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .isEmpty();
+ // Add a device to the network and assert that this device is included in the list of
+ // devices.
+ HdmiDeviceInfo infoPlayback = HdmiDeviceInfo.cecDeviceBuilder()
+ .setLogicalAddress(Constants.ADDR_PLAYBACK_3)
+ .setPhysicalAddress(0x1000)
+ .setPortId(PORT_1)
+ .setDeviceType(HdmiDeviceInfo.DEVICE_PLAYBACK)
+ .setVendorId(0x1000)
+ .setDisplayName("Playback 3")
+ .build();
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(infoPlayback);
+ mTestLooper.dispatchAll();
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .hasSize(1);
+
+ // HAL detects a hotplug out. Assert that this device gets removed from the list of devices.
+ mHdmiControlService.onHotplug(PORT_1, false);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .isEmpty();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index d104871f488a..df4aa5dac9df 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -19,6 +19,7 @@ import static com.android.server.hdmi.Constants.ABORT_UNRECOGNIZED_OPCODE;
import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
import static com.android.server.hdmi.Constants.ADDR_RECORDER_1;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
@@ -53,6 +54,7 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import java.util.concurrent.TimeUnit;
@SmallTest
@@ -61,6 +63,7 @@ import java.util.concurrent.TimeUnit;
/** Tests for {@link HdmiCecLocalDeviceTv} class. */
public class HdmiCecLocalDeviceTvTest {
private static final int TIMEOUT_MS = HdmiConfig.TIMEOUT_MS + 1;
+ private static final int PORT_1 = 1;
private static final String[] SADS_NOT_TO_QUERY = new String[]{
HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MPEG1,
@@ -90,6 +93,25 @@ public class HdmiCecLocalDeviceTvTest {
private int mTvPhysicalAddress;
private int mTvLogicalAddress;
private boolean mWokenUp;
+ private List<DeviceEventListener> mDeviceEventListeners = new ArrayList<>();
+
+ private class DeviceEventListener {
+ private HdmiDeviceInfo mDevice;
+ private int mStatus;
+
+ DeviceEventListener(HdmiDeviceInfo device, int status) {
+ this.mDevice = device;
+ this.mStatus = status;
+ }
+
+ int getStatus() {
+ return mStatus;
+ }
+
+ HdmiDeviceInfo getDeviceInfo() {
+ return mDevice;
+ }
+ }
@Mock
private AudioManager mAudioManager;
@@ -133,6 +155,11 @@ public class HdmiCecLocalDeviceTvTest {
AudioManager getAudioManager() {
return mAudioManager;
}
+
+ @Override
+ void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) {
+ mDeviceEventListeners.add(new DeviceEventListener(device, status));
+ }
};
mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService);
@@ -609,4 +636,147 @@ public class HdmiCecLocalDeviceTvTest {
ADDR_TV, ADDR_PLAYBACK_1);
assertThat(mNativeWrapper.getResultMessages()).contains(givePhysicalAddress);
}
+
+ @Test
+ public void hotplugDetectionActionClearsDevices() {
+ mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .isEmpty();
+ // Add a device to the network and assert that this device is included in the list of
+ // devices.
+ HdmiDeviceInfo infoPlayback = HdmiDeviceInfo.cecDeviceBuilder()
+ .setLogicalAddress(Constants.ADDR_PLAYBACK_2)
+ .setPhysicalAddress(0x1000)
+ .setPortId(PORT_1)
+ .setDeviceType(HdmiDeviceInfo.DEVICE_PLAYBACK)
+ .setVendorId(0x1000)
+ .setDisplayName("Playback 2")
+ .build();
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(infoPlayback);
+ mTestLooper.dispatchAll();
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .hasSize(1);
+ mDeviceEventListeners.clear();
+ assertThat(mDeviceEventListeners.size()).isEqualTo(0);
+
+ // HAL detects a hotplug out. Assert that this device stays in the list of devices.
+ mHdmiControlService.onHotplug(PORT_1, false);
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .hasSize(1);
+ assertThat(mDeviceEventListeners).isEmpty();
+ mTestLooper.dispatchAll();
+ // Make the device not acknowledge the poll message sent by the HotplugDetectionAction.
+ // Assert that this device is removed from the list of devices.
+ mNativeWrapper.setPollAddressResponse(Constants.ADDR_PLAYBACK_2, SendMessageResult.NACK);
+ for (int pollCount = 0; pollCount < HotplugDetectionAction.TIMEOUT_COUNT; pollCount++) {
+ mTestLooper.moveTimeForward(HotplugDetectionAction.POLLING_INTERVAL_MS_FOR_TV);
+ mTestLooper.dispatchAll();
+ }
+
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .isEmpty();
+ assertThat(mDeviceEventListeners.size()).isEqualTo(1);
+ assertThat(mDeviceEventListeners.get(0).getStatus())
+ .isEqualTo(HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
+ HdmiDeviceInfo removedDeviceInfo = mDeviceEventListeners.get(0).getDeviceInfo();
+ assertThat(removedDeviceInfo.getPortId()).isEqualTo(PORT_1);
+ assertThat(removedDeviceInfo.getLogicalAddress()).isEqualTo(Constants.ADDR_PLAYBACK_2);
+ assertThat(removedDeviceInfo.getPhysicalAddress()).isEqualTo(0x1000);
+ assertThat(removedDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_PLAYBACK);
+ }
+
+ @Test
+ public void hotplugDetectionActionClearsDevices_AudioSystem() {
+ mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .isEmpty();
+ // Add a device to the network and assert that this device is included in the list of
+ // devices.
+ HdmiDeviceInfo infoAudioSystem = HdmiDeviceInfo.cecDeviceBuilder()
+ .setLogicalAddress(ADDR_AUDIO_SYSTEM)
+ .setPhysicalAddress(0x1000)
+ .setPortId(PORT_1)
+ .setDeviceType(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM)
+ .setVendorId(0x1000)
+ .setDisplayName("Audio System")
+ .build();
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(infoAudioSystem);
+ mTestLooper.dispatchAll();
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .hasSize(1);
+ mDeviceEventListeners.clear();
+ assertThat(mDeviceEventListeners.size()).isEqualTo(0);
+
+ // HAL detects a hotplug out. Assert that this device stays in the list of devices.
+ mHdmiControlService.onHotplug(PORT_1, false);
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .hasSize(1);
+ assertThat(mDeviceEventListeners).isEmpty();
+ mTestLooper.dispatchAll();
+ // Make the device not acknowledge the poll message sent by the HotplugDetectionAction.
+ // Assert that this device is removed from the list of devices.
+ mNativeWrapper.setPollAddressResponse(ADDR_AUDIO_SYSTEM, SendMessageResult.NACK);
+ for (int pollCount = 0; pollCount < HotplugDetectionAction.TIMEOUT_COUNT; pollCount++) {
+ mTestLooper.moveTimeForward(HotplugDetectionAction.POLLING_INTERVAL_MS_FOR_TV);
+ mTestLooper.dispatchAll();
+ }
+
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .isEmpty();
+ assertThat(mDeviceEventListeners.size()).isEqualTo(1);
+ assertThat(mDeviceEventListeners.get(0).getStatus())
+ .isEqualTo(HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
+ HdmiDeviceInfo removedDeviceInfo = mDeviceEventListeners.get(0).getDeviceInfo();
+ assertThat(removedDeviceInfo.getPortId()).isEqualTo(PORT_1);
+ assertThat(removedDeviceInfo.getLogicalAddress()).isEqualTo(Constants.ADDR_AUDIO_SYSTEM);
+ assertThat(removedDeviceInfo.getPhysicalAddress()).isEqualTo(0x1000);
+ assertThat(removedDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
+ }
+
+ @Test
+ public void listenerInvokedIfPhysicalAddressReported() {
+ mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .isEmpty();
+ HdmiCecMessage reportPhysicalAddress =
+ HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ ADDR_PLAYBACK_2, 0x1000, HdmiDeviceInfo.DEVICE_PLAYBACK);
+ mNativeWrapper.onCecMessage(reportPhysicalAddress);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .hasSize(1);
+ assertThat(mDeviceEventListeners.size()).isEqualTo(1);
+ assertThat(mDeviceEventListeners.get(0).getStatus())
+ .isEqualTo(HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
+ }
+
+ @Test
+ public void listenerNotInvokedIfPhysicalAddressUnknown() {
+ mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .isEmpty();
+ HdmiCecMessage setOsdName = HdmiCecMessageBuilder.buildSetOsdNameCommand(
+ ADDR_PLAYBACK_2, ADDR_TV, "Playback 2");
+ mNativeWrapper.onCecMessage(setOsdName);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .hasSize(1);
+ assertThat(mDeviceEventListeners).isEmpty();
+
+ // When the device reports its physical address, the listener eventually is invoked.
+ HdmiCecMessage reportPhysicalAddress =
+ HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ ADDR_PLAYBACK_2, 0x1000, HdmiDeviceInfo.DEVICE_PLAYBACK);
+ mNativeWrapper.onCecMessage(reportPhysicalAddress);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .hasSize(1);
+ assertThat(mDeviceEventListeners.size()).isEqualTo(1);
+ assertThat(mDeviceEventListeners.get(0).getStatus())
+ .isEqualTo(HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
+
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java
index 42fa32cabc06..03532ae1cb1f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java
@@ -102,6 +102,8 @@ public class HdmiCecNetworkTest {
new HdmiPortInfo(5, HdmiPortInfo.PORT_OUTPUT, 0x0000, true, false, false);
mNativeWrapper.setPortInfo(mHdmiPortInfo);
mHdmiCecNetwork.initPortInfo();
+
+ mHdmiCecNetwork = mHdmiControlService.getHdmiCecNetwork();
}
@Test
@@ -142,7 +144,24 @@ public class HdmiCecNetworkTest {
}
@Test
+ public void physicalAddressToPort_localDevice_weAreSourceDevice() {
+ mNativeWrapper.setPhysicalAddress(0x2000);
+ mHdmiCecNetwork.initPortInfo();
+ assertThat(mHdmiCecNetwork.physicalAddressToPortId(0x2000))
+ .isEqualTo(Constants.CEC_SWITCH_HOME);
+ }
+
+ @Test
+ public void physicalAddressToPort_localDevice_weAreTv() {
+ mNativeWrapper.setPhysicalAddress(0x0000);
+ mHdmiCecNetwork.initPortInfo();
+ assertThat(mHdmiCecNetwork.physicalAddressToPortId(0x0000))
+ .isEqualTo(Constants.CEC_SWITCH_HOME);
+ }
+
+ @Test
public void localDevices_verifyOne_tv() {
+ mHdmiCecNetwork.clearLocalDevices();
mHdmiCecNetwork.addLocalDevice(HdmiDeviceInfo.DEVICE_TV,
new HdmiCecLocalDeviceTv(mHdmiControlService));
@@ -155,6 +174,7 @@ public class HdmiCecNetworkTest {
@Test
public void localDevices_verifyOne_playback() {
+ mHdmiCecNetwork.clearLocalDevices();
mHdmiCecNetwork.addLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK,
new HdmiCecLocalDevicePlayback(mHdmiControlService));
@@ -177,27 +197,26 @@ public class HdmiCecNetworkTest {
assertThat(cecDeviceInfo.getLogicalAddress()).isEqualTo(logicalAddress);
assertThat(cecDeviceInfo.getPhysicalAddress()).isEqualTo(
Constants.INVALID_PHYSICAL_ADDRESS);
- assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_RESERVED);
+ assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_PLAYBACK);
assertThat(cecDeviceInfo.getDisplayName()).isEqualTo(
HdmiUtils.getDefaultDeviceName(logicalAddress));
assertThat(cecDeviceInfo.getVendorId()).isEqualTo(Constants.VENDOR_ID_UNKNOWN);
assertThat(cecDeviceInfo.getDevicePowerStatus()).isEqualTo(
HdmiControlManager.POWER_STATUS_UNKNOWN);
- assertThat(mDeviceEventListenerStatuses).containsExactly(
- HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
+ assertThat(mDeviceEventListenerStatuses).isEmpty();
}
@Test
public void cecDevices_tracking_logicalAddressOnly_doesntNotifyAgain() throws Exception {
int logicalAddress = Constants.ADDR_PLAYBACK_1;
+ int physicalAddress = 0x1000;
mHdmiCecNetwork.handleCecMessage(
- HdmiCecMessageBuilder.buildActiveSource(logicalAddress, 0x1000));
+ HdmiCecMessageBuilder.buildActiveSource(logicalAddress, physicalAddress));
mHdmiCecNetwork.handleCecMessage(
- HdmiCecMessageBuilder.buildActiveSource(logicalAddress, 0x1000));
+ HdmiCecMessageBuilder.buildActiveSource(logicalAddress, physicalAddress));
- assertThat(mDeviceEventListenerStatuses).containsExactly(
- HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
+ assertThat(mDeviceEventListenerStatuses).isEmpty();
}
@Test
@@ -221,6 +240,9 @@ public class HdmiCecNetworkTest {
assertThat(cecDeviceInfo.getVendorId()).isEqualTo(Constants.VENDOR_ID_UNKNOWN);
assertThat(cecDeviceInfo.getDevicePowerStatus()).isEqualTo(
HdmiControlManager.POWER_STATUS_UNKNOWN);
+
+ assertThat(mDeviceEventListenerStatuses).containsExactly(
+ HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
}
@Test
@@ -238,11 +260,10 @@ public class HdmiCecNetworkTest {
physicalAddress, type));
- // ADD for logical address first detected
- // UPDATE for updating device with physical address
+ // ADD for physical address first detected
+ // no UPDATE, since physical address didn't change
assertThat(mDeviceEventListenerStatuses).containsExactly(
- HdmiControlManager.DEVICE_EVENT_ADD_DEVICE,
- HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE);
+ HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
}
@Test
@@ -259,11 +280,13 @@ public class HdmiCecNetworkTest {
assertThat(cecDeviceInfo.getLogicalAddress()).isEqualTo(logicalAddress);
assertThat(cecDeviceInfo.getPhysicalAddress()).isEqualTo(
Constants.INVALID_PHYSICAL_ADDRESS);
- assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_RESERVED);
+ assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_PLAYBACK);
assertThat(cecDeviceInfo.getVendorId()).isEqualTo(Constants.VENDOR_ID_UNKNOWN);
assertThat(cecDeviceInfo.getDisplayName()).isEqualTo(
HdmiUtils.getDefaultDeviceName(logicalAddress));
assertThat(cecDeviceInfo.getDevicePowerStatus()).isEqualTo(powerStatus);
+
+ assertThat(mDeviceEventListenerStatuses).isEmpty();
}
@Test
@@ -280,11 +303,13 @@ public class HdmiCecNetworkTest {
assertThat(cecDeviceInfo.getLogicalAddress()).isEqualTo(logicalAddress);
assertThat(cecDeviceInfo.getPhysicalAddress()).isEqualTo(
Constants.INVALID_PHYSICAL_ADDRESS);
- assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_RESERVED);
+ assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_PLAYBACK);
assertThat(cecDeviceInfo.getVendorId()).isEqualTo(Constants.VENDOR_ID_UNKNOWN);
assertThat(cecDeviceInfo.getDisplayName()).isEqualTo(osdName);
assertThat(cecDeviceInfo.getDevicePowerStatus()).isEqualTo(
HdmiControlManager.POWER_STATUS_UNKNOWN);
+
+ assertThat(mDeviceEventListenerStatuses).isEmpty();
}
@Test
@@ -300,12 +325,14 @@ public class HdmiCecNetworkTest {
assertThat(cecDeviceInfo.getLogicalAddress()).isEqualTo(logicalAddress);
assertThat(cecDeviceInfo.getPhysicalAddress()).isEqualTo(
Constants.INVALID_PHYSICAL_ADDRESS);
- assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_RESERVED);
+ assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_PLAYBACK);
assertThat(cecDeviceInfo.getDisplayName()).isEqualTo(
HdmiUtils.getDefaultDeviceName(logicalAddress));
assertThat(cecDeviceInfo.getVendorId()).isEqualTo(vendorId);
assertThat(cecDeviceInfo.getDevicePowerStatus()).isEqualTo(
HdmiControlManager.POWER_STATUS_UNKNOWN);
+
+ assertThat(mDeviceEventListenerStatuses).isEmpty();
}
@Test
@@ -364,12 +391,10 @@ public class HdmiCecNetworkTest {
assertThat(cecDeviceInfo.getPhysicalAddress()).isEqualTo(updatedPhysicalAddress);
assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(type);
- // ADD for logical address first detected
- // UPDATE for updating device with physical address
+ // ADD for physical address first detected
// UPDATE for updating device with new physical address
assertThat(mDeviceEventListenerStatuses).containsExactly(
HdmiControlManager.DEVICE_EVENT_ADD_DEVICE,
- HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE,
HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE);
}
@@ -431,7 +456,7 @@ public class HdmiCecNetworkTest {
assertThat(cecDeviceInfo.getLogicalAddress()).isEqualTo(logicalAddress);
assertThat(cecDeviceInfo.getPhysicalAddress()).isEqualTo(
Constants.INVALID_PHYSICAL_ADDRESS);
- assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_RESERVED);
+ assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_PLAYBACK);
assertThat(cecDeviceInfo.getDisplayName()).isEqualTo(
HdmiUtils.getDefaultDeviceName(logicalAddress));
assertThat(cecDeviceInfo.getVendorId()).isEqualTo(updatedVendorId);
@@ -453,9 +478,8 @@ public class HdmiCecNetworkTest {
assertThat(mHdmiCecNetwork.getSafeCecDevicesLocked()).isEmpty();
- assertThat(mDeviceEventListenerStatuses).containsExactly(
- HdmiControlManager.DEVICE_EVENT_ADD_DEVICE,
- HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
+ // Physical address never got reported, so no listeners are triggered
+ assertThat(mDeviceEventListenerStatuses).isEmpty();
}
@Test
@@ -472,7 +496,7 @@ public class HdmiCecNetworkTest {
assertThat(cecDeviceInfo.getLogicalAddress()).isEqualTo(logicalAddress);
assertThat(cecDeviceInfo.getPhysicalAddress()).isEqualTo(
Constants.INVALID_PHYSICAL_ADDRESS);
- assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_RESERVED);
+ assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_PLAYBACK);
assertThat(cecDeviceInfo.getVendorId()).isEqualTo(Constants.VENDOR_ID_UNKNOWN);
assertThat(cecDeviceInfo.getDisplayName()).isEqualTo(
HdmiUtils.getDefaultDeviceName(logicalAddress));
diff --git a/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java b/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java
index bda7cf66f685..e886e7dc1d60 100644
--- a/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java
@@ -57,14 +57,14 @@ public class BiasSchedulingTest extends AndroidTestCase {
}
public void testLowerBiasJobPreempted() throws Exception {
- for (int i = 0; i < JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; ++i) {
+ for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
JobInfo job = new JobInfo.Builder(100 + i, sJobServiceComponent)
.setBias(LOW_BIAS)
.setOverrideDeadline(0)
.build();
mJobScheduler.schedule(job);
}
- final int higherBiasJobId = 100 + JobSchedulerService.MAX_JOB_CONTEXTS_COUNT;
+ final int higherBiasJobId = 100 + JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT;
JobInfo jobHigher = new JobInfo.Builder(higherBiasJobId, sJobServiceComponent)
.setBias(HIGH_BIAS)
.setMinimumLatency(2000)
@@ -88,14 +88,14 @@ public class BiasSchedulingTest extends AndroidTestCase {
}
public void testHigherBiasJobNotPreempted() throws Exception {
- for (int i = 0; i < JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; ++i) {
+ for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
JobInfo job = new JobInfo.Builder(100 + i, sJobServiceComponent)
.setBias(HIGH_BIAS)
.setOverrideDeadline(0)
.build();
mJobScheduler.schedule(job);
}
- final int lowerBiasJobId = 100 + JobSchedulerService.MAX_JOB_CONTEXTS_COUNT;
+ final int lowerBiasJobId = 100 + JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT;
JobInfo jobLower = new JobInfo.Builder(lowerBiasJobId, sJobServiceComponent)
.setBias(LOW_BIAS)
.setMinimumLatency(2000)
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java
index b72b8d2ec6e8..d8f4349b95bf 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java
@@ -77,7 +77,7 @@ import java.util.concurrent.Executor;
@Presubmit
@RunWith(JUnit4.class)
-public class AppsFilterTest {
+public class AppsFilterImplTest {
private static final int DUMMY_CALLING_APPID = 10345;
private static final int DUMMY_TARGET_APPID = 10556;
@@ -98,9 +98,9 @@ public class AppsFilterTest {
}
@Mock
- AppsFilter.FeatureConfig mFeatureConfigMock;
+ AppsFilterImpl.FeatureConfig mFeatureConfigMock;
@Mock
- AppsFilter.StateProvider mStateProvider;
+ AppsFilterImpl.StateProvider mStateProvider;
@Mock
Executor mMockExecutor;
@Mock
@@ -204,11 +204,11 @@ public class AppsFilterTest {
MockitoAnnotations.initMocks(this);
doAnswer(invocation -> {
- ((AppsFilter.StateProvider.CurrentStateCallback) invocation.getArgument(0))
+ ((AppsFilterImpl.StateProvider.CurrentStateCallback) invocation.getArgument(0))
.currentState(mExisting, USER_INFO_LIST);
return new Object();
}).when(mStateProvider)
- .runWithState(any(AppsFilter.StateProvider.CurrentStateCallback.class));
+ .runWithState(any(AppsFilterImpl.StateProvider.CurrentStateCallback.class));
doAnswer(invocation -> {
((Runnable) invocation.getArgument(0)).run();
@@ -218,14 +218,14 @@ public class AppsFilterTest {
when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true);
when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))).thenAnswer(
(Answer<Boolean>) invocation ->
- ((AndroidPackage)invocation.getArgument(SYSTEM_USER)).getTargetSdkVersion()
+ ((AndroidPackage) invocation.getArgument(SYSTEM_USER)).getTargetSdkVersion()
>= Build.VERSION_CODES.R);
}
@Test
public void testSystemReadyPropogates() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -236,8 +236,8 @@ public class AppsFilterTest {
@Test
public void testQueriesAction_FilterMatches() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -259,8 +259,8 @@ public class AppsFilterTest {
}
@Test
public void testQueriesProtectedAction_FilterDoesNotMatch() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -308,8 +308,8 @@ public class AppsFilterTest {
@Test
public void testQueriesProvider_FilterMatches() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -333,8 +333,8 @@ public class AppsFilterTest {
@Test
public void testOnUserUpdated_FilterMatches() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
@@ -356,11 +356,11 @@ public class AppsFilterTest {
// adds new user
doAnswer(invocation -> {
- ((AppsFilter.StateProvider.CurrentStateCallback) invocation.getArgument(0))
+ ((AppsFilterImpl.StateProvider.CurrentStateCallback) invocation.getArgument(0))
.currentState(mExisting, USER_INFO_LIST_WITH_ADDED);
return new Object();
}).when(mStateProvider)
- .runWithState(any(AppsFilter.StateProvider.CurrentStateCallback.class));
+ .runWithState(any(AppsFilterImpl.StateProvider.CurrentStateCallback.class));
appsFilter.onUserCreated(ADDED_USER);
for (int subjectUserId : USER_ARRAY_WITH_ADDED) {
@@ -373,11 +373,11 @@ public class AppsFilterTest {
// delete user
doAnswer(invocation -> {
- ((AppsFilter.StateProvider.CurrentStateCallback) invocation.getArgument(0))
+ ((AppsFilterImpl.StateProvider.CurrentStateCallback) invocation.getArgument(0))
.currentState(mExisting, USER_INFO_LIST);
return new Object();
}).when(mStateProvider)
- .runWithState(any(AppsFilter.StateProvider.CurrentStateCallback.class));
+ .runWithState(any(AppsFilterImpl.StateProvider.CurrentStateCallback.class));
appsFilter.onUserDeleted(ADDED_USER);
for (int subjectUserId : USER_ARRAY) {
@@ -391,8 +391,8 @@ public class AppsFilterTest {
@Test
public void testQueriesDifferentProvider_Filters() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -416,8 +416,8 @@ public class AppsFilterTest {
@Test
public void testQueriesProviderWithSemiColon_FilterMatches() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -435,8 +435,8 @@ public class AppsFilterTest {
@Test
public void testQueriesAction_NoMatchingAction_Filters() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -452,8 +452,8 @@ public class AppsFilterTest {
@Test
public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -473,8 +473,8 @@ public class AppsFilterTest {
@Test
public void testNoQueries_Filters() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -490,7 +490,7 @@ public class AppsFilterTest {
@Test
public void testNoUsesLibrary_Filters() throws Exception {
- final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
+ final AppsFilterImpl appsFilter = new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
mMockExecutor, mMockPmInternal);
@@ -516,7 +516,7 @@ public class AppsFilterTest {
@Test
public void testUsesLibrary_DoesntFilter() throws Exception {
- final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
+ final AppsFilterImpl appsFilter = new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
mMockExecutor, mMockPmInternal);
@@ -543,7 +543,7 @@ public class AppsFilterTest {
@Test
public void testUsesOptionalLibrary_DoesntFilter() throws Exception {
- final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
+ final AppsFilterImpl appsFilter = new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
mMockExecutor, mMockPmInternal);
@@ -570,7 +570,7 @@ public class AppsFilterTest {
@Test
public void testUsesLibrary_ShareUid_DoesntFilter() throws Exception {
- final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
+ final AppsFilterImpl appsFilter = new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
mMockExecutor, mMockPmInternal);
@@ -602,8 +602,8 @@ public class AppsFilterTest {
@Test
public void testForceQueryable_SystemDoesntFilter() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -621,8 +621,8 @@ public class AppsFilterTest {
@Test
public void testForceQueryable_NonSystemFilters() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -638,9 +638,10 @@ public class AppsFilterTest {
@Test
public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"},
- false, null, mMockExecutor, mMockPmInternal);
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
+ new String[]{"com.some.package"}, false, null,
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -657,8 +658,8 @@ public class AppsFilterTest {
@Test
public void testSystemSignedTarget_DoesntFilter() throws CertificateException {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
appsFilter.onSystemReady();
@@ -686,9 +687,10 @@ public class AppsFilterTest {
@Test
public void testForceQueryableByDevice_NonSystemCaller_Filters() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"},
- false, null, mMockExecutor, mMockPmInternal);
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
+ new String[]{"com.some.package"}, false, null,
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -704,8 +706,8 @@ public class AppsFilterTest {
@Test
public void testSystemQueryable_DoesntFilter() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{},
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{},
true /* system force queryable */, null, mMockExecutor,
mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
@@ -723,8 +725,8 @@ public class AppsFilterTest {
@Test
public void testQueriesPackage_DoesntFilter() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -742,8 +744,8 @@ public class AppsFilterTest {
public void testNoQueries_FeatureOff_DoesntFilter() throws Exception {
when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class)))
.thenReturn(false);
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -759,8 +761,8 @@ public class AppsFilterTest {
@Test
public void testSystemUid_DoesntFilter() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -775,8 +777,8 @@ public class AppsFilterTest {
@Test
public void testSystemUidSecondaryUser_DoesntFilter() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -792,8 +794,8 @@ public class AppsFilterTest {
@Test
public void testNonSystemUid_NoCallingSetting_Filters() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -807,8 +809,8 @@ public class AppsFilterTest {
@Test
public void testNoTargetPackage_filters() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -838,7 +840,7 @@ public class AppsFilterTest {
.setOverlayTargetOverlayableName("overlayableName");
ParsingPackage actor = pkg("com.some.package.actor");
- final AppsFilter appsFilter = new AppsFilter(
+ final AppsFilterImpl appsFilter = new AppsFilterImpl(
mStateProvider,
mFeatureConfigMock,
new String[]{},
@@ -933,7 +935,7 @@ public class AppsFilterTest {
when(mMockPmInternal.getSharedUserPackages(any(Integer.class))).thenReturn(
actorSharedSettingPackages
);
- final AppsFilter appsFilter = new AppsFilter(
+ final AppsFilterImpl appsFilter = new AppsFilterImpl(
mStateProvider,
mFeatureConfigMock,
new String[]{},
@@ -985,8 +987,8 @@ public class AppsFilterTest {
@Test
public void testInitiatingApp_DoesntFilter() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -1003,8 +1005,8 @@ public class AppsFilterTest {
@Test
public void testUninstalledInitiatingApp_Filters() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -1021,8 +1023,8 @@ public class AppsFilterTest {
@Test
public void testOriginatingApp_Filters() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -1046,8 +1048,8 @@ public class AppsFilterTest {
@Test
public void testInstallingApp_DoesntFilter() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -1071,8 +1073,8 @@ public class AppsFilterTest {
@Test
public void testInstrumentation_DoesntFilter() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -1100,8 +1102,8 @@ public class AppsFilterTest {
@Test
public void testWhoCanSee() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -1173,8 +1175,8 @@ public class AppsFilterTest {
@Test
public void testOnChangeReport() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -1246,8 +1248,8 @@ public class AppsFilterTest {
@Test
public void testOnChangeReportedFilter() throws Exception {
- final AppsFilter appsFilter =
- new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -1270,6 +1272,53 @@ public class AppsFilterTest {
watcher.verifyNoChangeReported("shouldFilterApplication");
}
+ @Test
+ public void testAppsFilterRead() throws Exception {
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ mMockExecutor, mMockPmInternal);
+ simulateAddBasicAndroid(appsFilter);
+ appsFilter.onSystemReady();
+
+ PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
+ DUMMY_TARGET_APPID);
+ PackageSetting instrumentation = simulateAddPackage(appsFilter,
+ pkgWithInstrumentation("com.some.other.package", "com.some.package"),
+ DUMMY_CALLING_APPID);
+
+ final int hasProviderAppId = Process.FIRST_APPLICATION_UID + 1;
+ final int queriesProviderAppId = Process.FIRST_APPLICATION_UID + 2;
+ PackageSetting queriesProvider = simulateAddPackage(appsFilter,
+ pkgQueriesProvider("com.yet.some.other.package", "com.some.authority"),
+ queriesProviderAppId);
+ appsFilter.grantImplicitAccess(
+ hasProviderAppId, queriesProviderAppId, false /* retainOnUpdate */);
+
+ AppsFilterSnapshot snapshot = appsFilter.snapshot();
+ assertFalse(
+ snapshot.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target,
+ SYSTEM_USER));
+ assertFalse(
+ snapshot.shouldFilterApplication(DUMMY_TARGET_APPID, target, instrumentation,
+ SYSTEM_USER));
+
+ SparseArray<int[]> queriesProviderFilter =
+ snapshot.getVisibilityAllowList(queriesProvider, USER_ARRAY, mExisting);
+ assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)), contains(queriesProviderAppId));
+ assertTrue(snapshot.canQueryPackage(instrumentation.getPkg(),
+ target.getPackageName()));
+
+ // New changes don't affect the snapshot
+ appsFilter.removePackage(target, false);
+ assertTrue(
+ appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target,
+ SYSTEM_USER));
+ assertFalse(
+ snapshot.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target,
+ SYSTEM_USER));
+
+ }
+
private List<Integer> toList(int[] array) {
ArrayList<Integer> ret = new ArrayList<>(array.length);
for (int i = 0; i < array.length; i++) {
@@ -1282,7 +1331,7 @@ public class AppsFilterTest {
PackageSettingBuilder withBuilder(PackageSettingBuilder builder);
}
- private void simulateAddBasicAndroid(AppsFilter appsFilter) throws Exception {
+ private void simulateAddBasicAndroid(AppsFilterImpl appsFilter) throws Exception {
final Signature frameworkSignature = Mockito.mock(Signature.class);
final SigningDetails frameworkSigningDetails =
new SigningDetails(new Signature[]{frameworkSignature}, 1);
@@ -1291,17 +1340,17 @@ public class AppsFilterTest {
b -> b.setSigningDetails(frameworkSigningDetails));
}
- private PackageSetting simulateAddPackage(AppsFilter filter,
+ private PackageSetting simulateAddPackage(AppsFilterImpl filter,
ParsingPackage newPkgBuilder, int appId) {
return simulateAddPackage(filter, newPkgBuilder, appId, null /*settingBuilder*/);
}
- private PackageSetting simulateAddPackage(AppsFilter filter,
+ private PackageSetting simulateAddPackage(AppsFilterImpl filter,
ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action) {
return simulateAddPackage(filter, newPkgBuilder, appId, action, null /*sharedUserSetting*/);
}
- private PackageSetting simulateAddPackage(AppsFilter filter,
+ private PackageSetting simulateAddPackage(AppsFilterImpl filter,
ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action,
@Nullable SharedUserSetting sharedUserSetting) {
final PackageSetting setting =
@@ -1324,7 +1373,7 @@ public class AppsFilterTest {
return setting;
}
- private void simulateAddPackage(PackageSetting setting, AppsFilter filter,
+ private void simulateAddPackage(PackageSetting setting, AppsFilterImpl filter,
@Nullable SharedUserSetting sharedUserSetting) {
mExisting.put(setting.getPackageName(), setting);
if (sharedUserSetting != null) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index d99fbb12733c..a79a52c1c198 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -506,6 +506,11 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
}
@Override
+ void injectPostToHandlerDebounced(@NonNull final Object token, @NonNull final Runnable r) {
+ runOnHandler(r);
+ }
+
+ @Override
void injectEnforceCallingPermission(String permission, String message) {
if (!mCallerPermissions.contains(permission)) {
throw new SecurityException("Missing permission: " + permission);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 2b33088dd678..1877d45e5ce3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -189,8 +189,8 @@ public class PackageManagerServiceTest {
@Test
public void testKnownPackageToString_shouldNotGetUnknown() {
final List<String> packageNames = new ArrayList<>();
- for (int i = 0; i <= PackageManagerInternal.LAST_KNOWN_PACKAGE; i++) {
- packageNames.add(PackageManagerInternal.knownPackageToString(i));
+ for (int i = 0; i <= KnownPackages.LAST_KNOWN_PACKAGE; i++) {
+ packageNames.add(KnownPackages.knownPackageToString(i));
}
assertWithMessage(
"The Ids of KnownPackage should be continuous and the string representation "
@@ -205,7 +205,7 @@ public class PackageManagerServiceTest {
"The last KnownPackage Id should be assigned to PackageManagerInternal"
+ ".LAST_KNOWN_PACKAGE.").that(
knownPackageIds.get(knownPackageIds.size() - 1)).isEqualTo(
- PackageManagerInternal.LAST_KNOWN_PACKAGE);
+ KnownPackages.LAST_KNOWN_PACKAGE);
}
@Test
@@ -470,7 +470,7 @@ public class PackageManagerServiceTest {
private List<Integer> getKnownPackageIdsList() throws IllegalAccessException {
final ArrayList<Integer> knownPackageIds = new ArrayList<>();
- final Field[] allFields = PackageManagerInternal.class.getDeclaredFields();
+ final Field[] allFields = KnownPackages.class.getDeclaredFields();
for (Field field : allFields) {
final int modifier = field.getModifiers();
if (isPublic(modifier) && isStatic(modifier) && isFinal(modifier)
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 89450ffbc11d..3e81d601e477 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -931,6 +931,27 @@ public class PowerManagerServiceTest {
}
@Test
+ public void testInattentiveSleep_dreamEnds_goesToSleepAfterTimeout() {
+ setMinimumScreenOffTimeoutConfig(5);
+ setAttentiveTimeout(30000);
+ createService();
+ startSystem();
+
+ advanceTime(10000);
+ forceDream();
+ advanceTime(10000);
+ final String pkg = mContextSpy.getOpPackageName();
+ mService.getBinderServiceInstance().wakeUp(mClock.now(),
+ PowerManager.WAKE_REASON_DREAM_FINISHED, "PowerManagerServiceTest:DREAM_FINISHED",
+ pkg);
+ advanceTime(10001);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getBinderServiceInstance().getLastSleepReason()).isEqualTo(
+ PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE);
+ }
+
+ @Test
public void testScreenOffTimeout_goesToSleepAfterTimeout() {
final DisplayInfo info = new DisplayInfo();
info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
@@ -1684,6 +1705,58 @@ public class PowerManagerServiceTest {
}
@Test
+ public void testMultiDisplay_defaultDisplayCanDoze() {
+ createService();
+ startSystem();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+
+ forceDozing();
+ // Allow handleSandman() to be called asynchronously
+ advanceTime(500);
+ verify(mDreamManagerInternalMock).startDream(eq(true));
+ }
+
+ @Test
+ public void testMultiDisplay_twoDisplays_defaultDisplayCanDoze() {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = nonDefaultDisplayGroupId;
+ when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info);
+
+ createService();
+ startSystem();
+
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ forceDozing();
+
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_DOZING);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ // Allow handleSandman() to be called asynchronously
+ advanceTime(500);
+ verify(mDreamManagerInternalMock).startDream(eq(true));
+ }
+
+ @Test
public void testLastSleepTime_notUpdatedWhenDreaming() {
createService();
startSystem();
@@ -1697,6 +1770,99 @@ public class PowerManagerServiceTest {
}
@Test
+ public void testMultiDisplay_onlyOneDisplaySleeps_onWakefulnessChangedEventFires() {
+ createService();
+ startSystem();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ forceSleep();
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_ASLEEP);
+
+ verify(mNotifierMock).onPowerGroupWakefulnessChanged(eq(Display.DEFAULT_DISPLAY_GROUP),
+ eq(WAKEFULNESS_ASLEEP), anyInt(), eq(WAKEFULNESS_ASLEEP));
+ }
+
+ @Test
+ public void testMultiDisplay_bothDisplaysSleep_onWakefulnessChangedEventFiresCorrectly() {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = nonDefaultDisplayGroupId;
+ when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info);
+
+ createService();
+ startSystem();
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
+ null, null);
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
+ null, null);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_ASLEEP);
+
+ verify(mNotifierMock).onPowerGroupWakefulnessChanged(eq(nonDefaultDisplayGroupId),
+ eq(WAKEFULNESS_ASLEEP), anyInt(), eq(WAKEFULNESS_AWAKE));
+ verify(mNotifierMock).onPowerGroupWakefulnessChanged(eq(Display.DEFAULT_DISPLAY_GROUP),
+ eq(WAKEFULNESS_ASLEEP), anyInt(), eq(WAKEFULNESS_ASLEEP));
+ }
+
+ @Test
+ public void testMultiDisplay_separateWakeStates_onWakefulnessChangedEventFiresCorrectly() {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = nonDefaultDisplayGroupId;
+ when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info);
+
+ createService();
+ startSystem();
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ final String pkg = mContextSpy.getOpPackageName();
+ final Binder token = new Binder();
+ final String tag =
+ "testMultiDisplay_separateWakeStates_onWakefulnessChangedEventFiresCorrectly";
+ mService.getBinderServiceInstance().acquireWakeLock(token,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg,
+ null /* workSource */, null /* historyTag */, nonDefaultDisplay, null);
+
+ forceSleep();
+
+ // The wakelock should have kept the second display awake, and we should notify that the
+ // default display went to sleep.
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ verify(mNotifierMock).onPowerGroupWakefulnessChanged(eq(Display.DEFAULT_DISPLAY_GROUP),
+ eq(WAKEFULNESS_ASLEEP), anyInt(), eq(WAKEFULNESS_AWAKE));
+ verify(mNotifierMock, never()).onPowerGroupWakefulnessChanged(
+ eq(nonDefaultDisplayGroupId), anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
public void testGetFullPowerSavePolicy_returnsStateMachineResult() {
createService();
startSystem();
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 17464a6551d4..fb4d84cc75f2 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -283,7 +283,7 @@ public class AppStandbyControllerTests {
}
@Override
- boolean hasScheduleExactAlarm(String packageName, int uid) {
+ boolean hasExactAlarmPermission(String packageName, int uid) {
return mClockApps.contains(Pair.create(packageName, uid));
}
diff --git a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
index 4ed4c236535f..37c95f735d89 100644
--- a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
@@ -17,6 +17,7 @@
package com.android.server.utils;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -860,6 +861,54 @@ public class WatcherTest {
}
}
+ @Test
+ public void testWatchedSparseSetArray() {
+ final String name = "WatchedSparseSetArray";
+ WatchableTester tester;
+
+ // Test WatchedSparseSetArray
+ WatchedSparseSetArray array = new WatchedSparseSetArray();
+ tester = new WatchableTester(array, name);
+ tester.verify(0, "Initial array - no registration");
+ array.add(INDEX_A, 1);
+ tester.verify(0, "Updates with no registration");
+ tester.register();
+ tester.verify(0, "Updates with no registration");
+ array.add(INDEX_B, 2);
+ tester.verify(1, "Updates with registration");
+ array.add(INDEX_B, 4);
+ array.add(INDEX_C, 5);
+ tester.verify(3, "Updates with registration");
+ // Special methods
+ assertTrue(array.remove(INDEX_C, 5));
+ tester.verify(4, "Removed 5 from key 3");
+ array.remove(INDEX_B);
+ tester.verify(5, "Removed everything for key 2");
+
+ // Snapshot
+ {
+ WatchedSparseSetArray arraySnap = (WatchedSparseSetArray) array.snapshot();
+ tester.verify(5, "Generate snapshot");
+ // Verify that the snapshot is a proper copy of the source.
+ assertEquals("WatchedSparseSetArray snap same size",
+ array.size(), arraySnap.size());
+ for (int i = 0; i < array.size(); i++) {
+ ArraySet set = array.get(array.keyAt(i));
+ ArraySet setSnap = arraySnap.get(arraySnap.keyAt(i));
+ assertNotNull(set);
+ assertTrue(set.equals(setSnap));
+ }
+ array.add(INDEX_D, 9);
+ tester.verify(6, "Tick after snapshot");
+ // Verify that the array is sealed
+ verifySealed(name, ()->arraySnap.add(INDEX_D, 10));
+ assertTrue(!array.isSealed());
+ assertTrue(arraySnap.isSealed());
+ }
+ array.clear();
+ tester.verify(7, "Cleared all entries");
+ }
+
private static class IndexGenerator {
private final int mSeed;
private final Random mRandom;
@@ -1084,6 +1133,18 @@ public class WatcherTest {
assertEquals(a.equals(s), true);
a.put(rowIndex, colIndex, !a.get(rowIndex, colIndex));
assertEquals(a.equals(s), false);
+
+ // Verify copy-in/out
+ {
+ final String msg = name + " copy";
+ WatchedSparseBooleanMatrix copy = new WatchedSparseBooleanMatrix();
+ copy.copyFrom(matrix);
+ final int end = copy.size();
+ assertTrue(msg + " size mismatch " + end + " " + matrix.size(), end == matrix.size());
+ for (int i = 0; i < end; i++) {
+ assertEquals(copy.keyAt(i), keys[i]);
+ }
+ }
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
index 24ff3f96100a..73e409abf0c1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -31,6 +31,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.mock;
import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
@@ -350,7 +351,7 @@ public class ActivityStartInterceptorTest {
assertEquals(1, mActivityInterceptorCallbacks.size());
final ActivityInterceptorCallback callback = mActivityInterceptorCallbacks.valueAt(0);
spyOn(callback);
- mInterceptor.onActivityLaunched(null, null);
+ mInterceptor.onActivityLaunched(null, mock(ActivityRecord.class));
verify(callback, times(1)).onActivityLaunched(any(), any(), any());
}
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 91692676e216..605726c0e804 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -682,31 +682,43 @@ public class DisplayContentTests extends WindowTestsBase {
final int baseWidth = 1440;
final int baseHeight = 2560;
final int baseDensity = 300;
+ final float baseXDpi = 60;
+ final float baseYDpi = 60;
- displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
+ displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity, baseYDpi,
+ baseYDpi);
final int maxWidth = 300;
- final int resultingHeight = (maxWidth * baseHeight) / baseWidth;
- final int resultingDensity = (baseDensity * maxWidth) / baseWidth;
+ final float ratioChange = maxWidth / (float) baseWidth;
+ final int resultingHeight = (int) (baseHeight * ratioChange);
+ final int resultingDensity = (int) (baseDensity * ratioChange);
+ final float resultingXDpi = baseXDpi * ratioChange;
+ final float resultingYDpi = baseYDpi * ratioChange;
displayContent.setMaxUiWidth(maxWidth);
- verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
+ verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity, resultingXDpi,
+ resultingYDpi);
// Assert setting values again does not change;
- displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
- verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
+ displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity, baseXDpi,
+ baseYDpi);
+ verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity, resultingXDpi,
+ resultingYDpi);
final int smallerWidth = 200;
final int smallerHeight = 400;
final int smallerDensity = 100;
// Specify smaller dimension, verify that it is honored
- displayContent.updateBaseDisplayMetrics(smallerWidth, smallerHeight, smallerDensity);
- verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
+ displayContent.updateBaseDisplayMetrics(smallerWidth, smallerHeight, smallerDensity,
+ baseXDpi, baseYDpi);
+ verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity, baseXDpi,
+ baseYDpi);
// Verify that setting the max width to a greater value than the base width has no effect
displayContent.setMaxUiWidth(maxWidth);
- verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
+ verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity, baseXDpi,
+ baseYDpi);
}
@Test
@@ -716,11 +728,14 @@ public class DisplayContentTests extends WindowTestsBase {
final int baseWidth = 1280;
final int baseHeight = 720;
final int baseDensity = 320;
+ final float baseXDpi = 60;
+ final float baseYDpi = 60;
displayContent.mInitialDisplayWidth = baseWidth;
displayContent.mInitialDisplayHeight = baseHeight;
displayContent.mInitialDisplayDensity = baseDensity;
- displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
+ displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity, baseXDpi,
+ baseYDpi);
final int forcedWidth = 1920;
final int forcedHeight = 1080;
@@ -741,11 +756,14 @@ public class DisplayContentTests extends WindowTestsBase {
final int baseWidth = 1280;
final int baseHeight = 720;
final int baseDensity = 320;
+ final float baseXDpi = 60;
+ final float baseYDpi = 60;
displayContent.mInitialDisplayWidth = baseWidth;
displayContent.mInitialDisplayHeight = baseHeight;
displayContent.mInitialDisplayDensity = baseDensity;
- displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
+ displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity, baseXDpi,
+ baseYDpi);
displayContent.setMaxUiWidth(baseWidth);
@@ -767,11 +785,14 @@ public class DisplayContentTests extends WindowTestsBase {
final int baseWidth = 1280;
final int baseHeight = 720;
final int baseDensity = 320;
+ final float baseXDpi = 60;
+ final float baseYDpi = 60;
displayContent.mInitialDisplayWidth = baseWidth;
displayContent.mInitialDisplayHeight = baseHeight;
displayContent.mInitialDisplayDensity = baseDensity;
- displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
+ displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity, baseXDpi,
+ baseYDpi);
final int forcedDensity = 600;
@@ -2050,6 +2071,32 @@ public class DisplayContentTests extends WindowTestsBase {
verify(mDisplayContent, never()).showImeScreenshot();
}
+ @UseTestDisplay(addWindows = {W_INPUT_METHOD})
+ @Test
+ public void testShowImeScreenshot_removeCurSnapshotBeforeCreateNext() {
+ final Task rootTask = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+ final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
+ final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
+
+ mDisplayContent.setImeLayeringTarget(win);
+ mDisplayContent.setImeInputTarget(win);
+ spyOn(mDisplayContent);
+ spyOn(mDisplayContent.mInputMethodWindow);
+ doReturn(true).when(mDisplayContent.mInputMethodWindow).isVisible();
+ mDisplayContent.getInsetsStateController().getImeSourceProvider().setImeShowing(true);
+
+ // Verify when the timing of 2 showImeScreenshot invocations are very close, will first
+ // detach the current snapshot then create the next one.
+ mDisplayContent.showImeScreenshot();
+ DisplayContent.ImeScreenshot curSnapshot = mDisplayContent.mImeScreenshot;
+ spyOn(curSnapshot);
+ mDisplayContent.showImeScreenshot();
+ verify(curSnapshot).detach(any());
+ assertNotNull(mDisplayContent.mImeScreenshot);
+ assertNotEquals(curSnapshot, mDisplayContent.mImeScreenshot);
+ }
+
@Test
public void testRotateBounds_keepSamePhysicalPosition() {
final DisplayContent dc =
@@ -2487,6 +2534,16 @@ public class DisplayContentTests extends WindowTestsBase {
assertEquals(expectedBaseDensity, displayContent.mBaseDisplayDensity);
}
+ private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
+ int expectedBaseHeight, int expectedBaseDensity, float expectedBaseXDpi,
+ float expectedBaseYDpi) {
+ assertEquals(expectedBaseWidth, displayContent.mBaseDisplayWidth);
+ assertEquals(expectedBaseHeight, displayContent.mBaseDisplayHeight);
+ assertEquals(expectedBaseDensity, displayContent.mBaseDisplayDensity);
+ assertEquals(expectedBaseXDpi, displayContent.mBaseDisplayPhysicalXDpi, 1.0f /* delta */);
+ assertEquals(expectedBaseYDpi, displayContent.mBaseDisplayPhysicalYDpi, 1.0f /* delta */);
+ }
+
private void updateFocusedWindow() {
mWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false /* updateInputWindows */);
}
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 f570005f99cc..ea98b6b17e83 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -131,6 +131,11 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
+ public void onPowerGroupWakefulnessChanged(int groupId, int wakefulness,
+ @GoToSleepReason int pmSleepReason, int globalWakefulness) {
+ }
+
+ @Override
public void screenTurningOn(int displayId, ScreenOnListener screenOnListener) {
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 3330ca982068..6c1c0865446e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -53,6 +53,8 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.util.ArrayMap;
@@ -73,6 +75,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
/**
* Build/Install/Run:
@@ -589,6 +592,48 @@ public class TransitionTests extends WindowTestsBase {
}
@Test
+ public void testTransitionBounds() {
+ registerTestTransitionPlayer();
+ final int offset = 10;
+ final Function<WindowContainer<?>, TransitionInfo.Change> test = wc -> {
+ final Transition transition = wc.mTransitionController.createTransition(TRANSIT_OPEN);
+ transition.collect(wc);
+ final int nextRotation = (wc.getWindowConfiguration().getRotation() + 1) % 4;
+ wc.getWindowConfiguration().setRotation(nextRotation);
+ wc.getWindowConfiguration().setDisplayRotation(nextRotation);
+ final Rect bounds = wc.getWindowConfiguration().getBounds();
+ // Flip the bounds with offset.
+ wc.getWindowConfiguration().setBounds(
+ new Rect(offset, offset, bounds.height(), bounds.width()));
+ final int flags = 0;
+ final TransitionInfo info = Transition.calculateTransitionInfo(transition.mType, flags,
+ Transition.calculateTargets(transition.mParticipants, transition.mChanges),
+ transition.mChanges);
+ transition.abort();
+ return info.getChanges().get(0);
+ };
+
+ final ActivityRecord app = createActivityRecord(mDisplayContent);
+ final TransitionInfo.Change changeOfActivity = test.apply(app);
+ // There will be letterbox if the activity bounds don't match parent, so always use its
+ // parent bounds for animation.
+ assertEquals(app.getParent().getBounds(), changeOfActivity.getEndAbsBounds());
+ final int endRotation = app.mTransitionController.useShellTransitionsRotation()
+ ? app.getWindowConfiguration().getRotation()
+ // Without shell rotation, fixed rotation is done by core so the info should not
+ // contain rotation change.
+ : app.getParent().getWindowConfiguration().getRotation();
+ assertEquals(endRotation, changeOfActivity.getEndRotation());
+
+ // Non-activity target always uses its configuration for end info.
+ final Task task = app.getTask();
+ final TransitionInfo.Change changeOfTask = test.apply(task);
+ assertEquals(task.getBounds(), changeOfTask.getEndAbsBounds());
+ assertEquals(new Point(offset, offset), changeOfTask.getEndRelOffset());
+ assertEquals(task.getWindowConfiguration().getRotation(), changeOfTask.getEndRotation());
+ }
+
+ @Test
public void testDisplayRotationChange() {
final Task task = createActivityRecord(mDisplayContent).getTask();
final WindowState statusBar = createWindow(null, TYPE_STATUS_BAR, "statusBar");
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 bb0c7f7000ab..b6998d84afa3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -503,7 +503,6 @@ public class WindowStateTests extends WindowTestsBase {
win.applyWithNextDraw(t -> handledT[0] = t);
assertTrue(win.useBLASTSync());
final SurfaceControl.Transaction drawT = new StubTransaction();
- win.prepareDrawHandlers();
assertTrue(win.finishDrawing(drawT, Integer.MAX_VALUE));
assertEquals(drawT, handledT[0]);
assertFalse(win.useBLASTSync());
@@ -855,12 +854,13 @@ public class WindowStateTests extends WindowTestsBase {
assertTrue(mAtm.mActiveUids.hasNonAppVisibleWindow(uid));
}
- @UseTestDisplay(addWindows = W_ACTIVITY)
+ @UseTestDisplay(addWindows = {W_ACTIVITY, W_INPUT_METHOD})
@Test
public void testNeedsRelativeLayeringToIme_notAttached() {
WindowState sameTokenWindow = createWindow(null, TYPE_BASE_APPLICATION, mAppWindow.mToken,
"SameTokenWindow");
mDisplayContent.setImeLayeringTarget(mAppWindow);
+ makeWindowVisible(mImeWindow);
sameTokenWindow.mActivityRecord.getRootTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
assertTrue(sameTokenWindow.needsRelativeLayeringToIme());
sameTokenWindow.removeImmediately();
@@ -873,6 +873,7 @@ public class WindowStateTests extends WindowTestsBase {
WindowState sameTokenWindow = createWindow(null, TYPE_APPLICATION_STARTING,
mAppWindow.mToken, "SameTokenWindow");
mDisplayContent.setImeLayeringTarget(mAppWindow);
+ makeWindowVisible(mImeWindow);
sameTokenWindow.mActivityRecord.getRootTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
assertFalse(sameTokenWindow.needsRelativeLayeringToIme());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 0f223ca037ee..2df1d23c0497 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -274,6 +274,7 @@ public class ZOrderingTests extends WindowTestsBase {
"imeAppTargetChildBelowWindow");
mDisplayContent.setImeLayeringTarget(imeAppTarget);
+ makeWindowVisible(mImeWindow);
mDisplayContent.assignChildLayers(mTransaction);
// Ime should be above all app windows except for child windows that are z-ordered above it
@@ -599,6 +600,7 @@ public class ZOrderingTests extends WindowTestsBase {
WINDOWING_MODE_MULTI_WINDOW);
mDisplayContent.setImeLayeringTarget(mAppWindow);
mDisplayContent.setImeInputTarget(mAppWindow);
+ makeWindowVisible(mImeWindow);
// Create a popupWindow
assertWindowHigher(mImeWindow, mAppWindow);
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerService.java b/services/translation/java/com/android/server/translation/TranslationManagerService.java
index 27b254a304ff..e8c989280a0e 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerService.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerService.java
@@ -225,12 +225,12 @@ public final class TranslationManagerService
@Override
public void registerUiTranslationStateCallback(IRemoteCallback callback, int userId) {
- TranslationManagerServiceImpl service;
synchronized (mLock) {
- service = getServiceForUserLocked(userId);
- }
- if (service != null) {
- service.registerUiTranslationStateCallback(callback, Binder.getCallingUid());
+ final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
+ if (service != null) {
+ service.registerUiTranslationStateCallbackLocked(callback,
+ Binder.getCallingUid());
+ }
}
}
@@ -297,7 +297,7 @@ public final class TranslationManagerService
/**
* Dump the service state into the given stream. You run "adb shell dumpsys translation".
- */
+ */
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
index 3833ceb3122e..d3a589668808 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
@@ -22,9 +22,13 @@ import static android.view.translation.UiTranslationManager.EXTRA_SOURCE_LOCALE;
import static android.view.translation.UiTranslationManager.EXTRA_STATE;
import static android.view.translation.UiTranslationManager.EXTRA_TARGET_LOCALE;
import static android.view.translation.UiTranslationManager.STATE_UI_TRANSLATION_FINISHED;
+import static android.view.translation.UiTranslationManager.STATE_UI_TRANSLATION_PAUSED;
+import static android.view.translation.UiTranslationManager.STATE_UI_TRANSLATION_RESUMED;
+import static android.view.translation.UiTranslationManager.STATE_UI_TRANSLATION_STARTED;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
@@ -38,7 +42,9 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.service.translation.TranslationServiceInfo;
import android.util.ArraySet;
+import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.autofill.AutofillId;
import android.view.inputmethod.InputMethodInfo;
import android.view.translation.ITranslationServiceCallback;
@@ -68,6 +74,8 @@ final class TranslationManagerServiceImpl extends
AbstractPerUserSystemService<TranslationManagerServiceImpl, TranslationManagerService> {
private static final String TAG = "TranslationManagerServiceImpl";
+ @SuppressLint("IsLoggableTagLength")
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@GuardedBy("mLock")
@Nullable
@@ -83,13 +91,19 @@ final class TranslationManagerServiceImpl extends
@GuardedBy("mLock")
private WeakReference<ActivityTokens> mLastActivityTokens;
- private ActivityTaskManagerInternal mActivityTaskManagerInternal;
+ private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
private final TranslationServiceRemoteCallback mRemoteServiceCallback =
new TranslationServiceRemoteCallback();
private final RemoteCallbackList<IRemoteCallback> mTranslationCapabilityCallbacks =
new RemoteCallbackList<>();
- private final ArraySet<IBinder> mWaitingFinishedCallbackActivities = new ArraySet();
+ private final ArraySet<IBinder> mWaitingFinishedCallbackActivities = new ArraySet<>();
+
+ /**
+ * Key is translated activity uid, value is the specification and state for the translation.
+ */
+ @GuardedBy("mLock")
+ private final SparseArray<ActiveTranslation> mActiveTranslations = new SparseArray<>();
protected TranslationManagerServiceImpl(
@NonNull TranslationManagerService master,
@@ -231,6 +245,7 @@ final class TranslationManagerServiceImpl extends
if (state == STATE_UI_TRANSLATION_FINISHED) {
mWaitingFinishedCallbackActivities.add(token);
}
+
IBinder activityToken = taskTopActivityTokens.getActivityToken();
try {
taskTopActivityTokens.getApplicationThread().updateUiTranslationState(
@@ -243,9 +258,46 @@ final class TranslationManagerServiceImpl extends
ComponentName componentName = mActivityTaskManagerInternal.getActivityName(activityToken);
int translationActivityUid =
getActivityUidByComponentName(getContext(), componentName, getUserId());
+ String packageName = componentName.getPackageName();
if (state != STATE_UI_TRANSLATION_FINISHED) {
- invokeCallbacks(state, sourceSpec, targetSpec, componentName.getPackageName(),
+ invokeCallbacks(state, sourceSpec, targetSpec, packageName, translationActivityUid);
+ updateActiveTranslations(state, sourceSpec, targetSpec, packageName,
translationActivityUid);
+ } else {
+ if (mActiveTranslations.contains(translationActivityUid)) {
+ mActiveTranslations.delete(translationActivityUid);
+ } else {
+ Slog.w(TAG, "Finishing translation for activity with uid=" + translationActivityUid
+ + " but no active translation was found for it");
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void updateActiveTranslations(int state, TranslationSpec sourceSpec,
+ TranslationSpec targetSpec, String packageName, int translationActivityUid) {
+ // Keep track of active translations so that we can trigger callbacks that are
+ // registered after translation has started.
+ switch (state) {
+ case STATE_UI_TRANSLATION_STARTED: {
+ ActiveTranslation activeTranslation = new ActiveTranslation(sourceSpec,
+ targetSpec, packageName);
+ mActiveTranslations.put(translationActivityUid, activeTranslation);
+ break;
+ }
+ case STATE_UI_TRANSLATION_PAUSED:
+ case STATE_UI_TRANSLATION_RESUMED: {
+ ActiveTranslation activeTranslation = mActiveTranslations.get(
+ translationActivityUid);
+ if (activeTranslation != null) {
+ activeTranslation.isPaused = (state == STATE_UI_TRANSLATION_PAUSED);
+ } else {
+ Slog.w(TAG, "Pausing or resuming translation for activity with uid="
+ + translationActivityUid
+ + " but no active translation was found for it");
+ }
+ break;
+ }
}
}
@@ -289,49 +341,105 @@ final class TranslationManagerServiceImpl extends
private void invokeCallbacks(
int state, TranslationSpec sourceSpec, TranslationSpec targetSpec, String packageName,
int translationActivityUid) {
- Bundle res = new Bundle();
- res.putInt(EXTRA_STATE, state);
+ Bundle result = createResultForCallback(state, sourceSpec, targetSpec, packageName);
+ if (mCallbacks.getRegisteredCallbackCount() == 0) {
+ return;
+ }
+ List<InputMethodInfo> enabledInputMethods = getEnabledInputMethods();
+ mCallbacks.broadcast((callback, uid) -> {
+ invokeCallback((int) uid, translationActivityUid, callback, result,
+ enabledInputMethods);
+ });
+ }
+
+ private List<InputMethodInfo> getEnabledInputMethods() {
+ return LocalServices.getService(InputMethodManagerInternal.class)
+ .getEnabledInputMethodListAsUser(mUserId);
+ }
+
+ private Bundle createResultForCallback(
+ int state, TranslationSpec sourceSpec, TranslationSpec targetSpec, String packageName) {
+ Bundle result = new Bundle();
+ result.putInt(EXTRA_STATE, state);
// TODO(177500482): Store the locale pair so it can be sent for RESUME events.
if (sourceSpec != null) {
- res.putSerializable(EXTRA_SOURCE_LOCALE, sourceSpec.getLocale());
- res.putSerializable(EXTRA_TARGET_LOCALE, targetSpec.getLocale());
+ result.putSerializable(EXTRA_SOURCE_LOCALE, sourceSpec.getLocale());
+ result.putSerializable(EXTRA_TARGET_LOCALE, targetSpec.getLocale());
}
- res.putString(EXTRA_PACKAGE_NAME, packageName);
- // TODO(177500482): Only support the *current* Input Method.
- List<InputMethodInfo> enabledInputMethods =
- LocalServices.getService(InputMethodManagerInternal.class)
- .getEnabledInputMethodListAsUser(mUserId);
- mCallbacks.broadcast((callback, uid) -> {
- if ((int) uid == translationActivityUid) {
- try {
- callback.sendResult(res);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to invoke UiTranslationStateCallback: " + e);
- }
- return;
- }
- // Code here is non-optimal since it's temporary..
- boolean isIme = false;
- for (InputMethodInfo inputMethod : enabledInputMethods) {
- if ((int) uid == inputMethod.getServiceInfo().applicationInfo.uid) {
- isIme = true;
- }
- }
- // TODO(177500482): Invoke it for the application being translated too.
- if (!isIme) {
- return;
- }
+ result.putString(EXTRA_PACKAGE_NAME, packageName);
+ return result;
+ }
+
+ private void invokeCallback(
+ int callbackSourceUid, int translationActivityUid, IRemoteCallback callback,
+ Bundle result, List<InputMethodInfo> enabledInputMethods) {
+ if (callbackSourceUid == translationActivityUid) {
+ // Invoke callback for the application being translated.
try {
- callback.sendResult(res);
+ callback.sendResult(result);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to invoke UiTranslationStateCallback: " + e);
}
- });
+ return;
+ }
+
+ // TODO(177500482): Only support the *current* Input Method.
+ // Code here is non-optimal since it's temporary..
+ boolean isIme = false;
+ for (InputMethodInfo inputMethod : enabledInputMethods) {
+ if (callbackSourceUid == inputMethod.getServiceInfo().applicationInfo.uid) {
+ isIme = true;
+ break;
+ }
+ }
+
+ if (!isIme) {
+ return;
+ }
+ try {
+ callback.sendResult(result);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to invoke UiTranslationStateCallback: " + e);
+ }
}
- public void registerUiTranslationStateCallback(IRemoteCallback callback, int sourceUid) {
+ @GuardedBy("mLock")
+ public void registerUiTranslationStateCallbackLocked(IRemoteCallback callback, int sourceUid) {
mCallbacks.register(callback, sourceUid);
- // TODO(177500482): trigger the callback here if we're already translating the UI.
+
+ if (mActiveTranslations.size() == 0) {
+ return;
+ }
+
+ // Trigger the callback for already active translations.
+ List<InputMethodInfo> enabledInputMethods = getEnabledInputMethods();
+ for (int i = 0; i < mActiveTranslations.size(); i++) {
+ int activeTranslationUid = mActiveTranslations.keyAt(i);
+ ActiveTranslation activeTranslation = mActiveTranslations.valueAt(i);
+ if (activeTranslation == null) {
+ continue;
+ }
+ String packageName = activeTranslation.packageName;
+ if (DEBUG) {
+ Slog.d(TAG, "Triggering callback for sourceUid=" + sourceUid
+ + " for translated activity with uid=" + activeTranslationUid
+ + "packageName=" + packageName + " isPaused=" + activeTranslation.isPaused);
+ }
+
+ Bundle startedResult = createResultForCallback(STATE_UI_TRANSLATION_STARTED,
+ activeTranslation.sourceSpec, activeTranslation.targetSpec,
+ packageName);
+ invokeCallback(sourceUid, activeTranslationUid, callback, startedResult,
+ enabledInputMethods);
+ if (activeTranslation.isPaused) {
+ // Also send event so callback owners know that translation was started then paused.
+ Bundle pausedResult = createResultForCallback(STATE_UI_TRANSLATION_PAUSED,
+ activeTranslation.sourceSpec, activeTranslation.targetSpec,
+ packageName);
+ invokeCallback(sourceUid, activeTranslationUid, callback, pausedResult,
+ enabledInputMethods);
+ }
+ }
}
public void unregisterUiTranslationStateCallback(IRemoteCallback callback) {
@@ -376,4 +484,18 @@ final class TranslationManagerServiceImpl extends
notifyClientsTranslationCapability(capability);
}
}
+
+ private static final class ActiveTranslation {
+ public final TranslationSpec sourceSpec;
+ public final TranslationSpec targetSpec;
+ public final String packageName;
+ public boolean isPaused = false;
+
+ private ActiveTranslation(TranslationSpec sourceSpec, TranslationSpec targetSpec,
+ String packageName) {
+ this.sourceSpec = sourceSpec;
+ this.targetSpec = targetSpec;
+ this.packageName = packageName;
+ }
+ }
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index da54c329d5be..84bc21ced3b6 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -600,6 +600,9 @@ public class UsageStatsService extends SystemService implements
@Override public void onUidCachedChanged(int uid, boolean cached) {
}
+
+ @Override public void onUidProcAdjChanged(int uid) {
+ }
};
@Override
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 8880bc492de7..8d7fab4d101f 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4379,12 +4379,14 @@ public class CarrierConfigManager {
* The data stall recovery timers array in milliseconds, each element is the delay before
* performining next recovery action.
*
- * The default value of timers array are: [180000ms, 180000ms, 180000ms] (3 minutes)
+ * The default value of timers array are: [180000ms, 180000ms, 180000ms, 180000ms] (3 minutes)
* Array[0]: It's the timer between RECOVERY_ACTION GET_DATA_CALL_LIST and CLEANUP, if data
* stall symptom still occurred, it will perform next recovery action after 180000ms.
- * Array[1]: It's the timer between RECOVERY_ACTION CLEANUP and RADIO_RESTART, if data stall
+ * Array[1]: It's the timer between RECOVERY_ACTION CLEANUP and RE-REGISTER, if data stall
* symptom still occurred, it will perform next recovery action after 180000ms.
- * Array[2]: It's the timer between RECOVERY_ACTION RADIO_RESTART and RESET_MODEM, if data stall
+ * Array[2]: It's the timer between RECOVERY_ACTION RE-REGISTER and RADIO_RESTART, if data stall
+ * symptom still occurred, it will perform next recovery action after 180000ms.
+ * Array[3]: It's the timer between RECOVERY_ACTION RADIO_RESTART and RESET_MODEM, if data stall
* symptom still occurred, it will perform next recovery action after 180000ms.
*
* See the {@code RECOVERY_ACTION_*} constants in
@@ -4404,7 +4406,7 @@ public class CarrierConfigManager {
* RECOVERY_ACTION_CLEANUP to true, then it can be ignored to speed up the recovery
* action procedure.
*
- * The default value of boolean array are: [false, false, false, false]
+ * The default value of boolean array are: [false, false, true, false, false]
* Array[0]: When performing the recovery action, we can use this boolean value to determine
* if we need to perform RECOVERY_ACTION_GET_DATA_CALL_LIST.
* Array[1]: If data stall symptom still occurred, we can use this boolean value to determine
@@ -4414,8 +4416,10 @@ public class CarrierConfigManager {
* variable of action RECOVERY_ACTION_CLEANUP to true, then it can be ignored to speed up the
* recovery action procedure.
* Array[2]: If data stall symptom still occurred, we can use this boolean value to determine
- * if we need to perform RECOVERY_ACTION_RADIO_RESTART.
+ * if we need to perform RE-REGISTER.
* Array[3]: If data stall symptom still occurred, we can use this boolean value to determine
+ * if we need to perform RECOVERY_ACTION_RADIO_RESTART.
+ * Array[4]: If data stall symptom still occurred, we can use this boolean value to determine
* if we need to perform RECOVERY_ACTION_MODEM_RESET.
*
* See the {@code RECOVERY_ACTION_*} constants in
@@ -9159,9 +9163,9 @@ public class CarrierConfigManager {
SubscriptionManager.USAGE_SETTING_UNKNOWN);
// Default data stall recovery configurations.
sDefaults.putLongArray(KEY_DATA_STALL_RECOVERY_TIMERS_LONG_ARRAY,
- new long[] {180000, 180000, 180000});
+ new long[] {180000, 180000, 180000, 180000});
sDefaults.putBooleanArray(KEY_DATA_STALL_RECOVERY_SHOULD_SKIP_BOOL_ARRAY,
- new boolean[] {false, false, false, false});
+ new boolean[] {false, false, true, false, false});
}
/**
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index fc9acb81d408..7c7bf0a21c3f 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -3216,6 +3216,11 @@ public class SubscriptionManager {
*
* @param subId sub id
* @param callbackIntent pending intent that will be sent after operation is done.
+ *
+ * to-be-deprecated this API is a duplicate of {@link EuiccManager#switchToSubscription(int,
+ * PendingIntent)} and does not support Multiple Enabled Profile(MEP). Apps should use
+ * {@link EuiccManager#switchToSubscription(int, PendingIntent)} or
+ * {@link EuiccManager#switchToSubscription(int, int, PendingIntent)} instead.
*/
@RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void switchToSubscription(int subId, @NonNull PendingIntent callbackIntent) {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index a425ee0ed969..d1319ac095ed 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -17,7 +17,6 @@
package com.android.server.wm.flicker.close
-import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -99,38 +98,6 @@ class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio
super.statusBarLayerRotatesScales()
}
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun launcherLayerReplacesApp() {
- // This test doesn't work in shell transitions because of b/206086894
- assumeFalse(isShellTransitionsEnabled)
- super.launcherLayerReplacesApp()
- }
-
- @FlakyTest(bugId = 214452854)
- @Test
- fun launcherLayerReplacesApp_shellTransit() {
- assumeTrue(isShellTransitionsEnabled)
- super.launcherLayerReplacesApp()
- }
-
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun entireScreenCovered() {
- // This test doesn't work in shell transitions because of b/206086894
- assumeFalse(isShellTransitionsEnabled)
- super.entireScreenCovered()
- }
-
- @FlakyTest(bugId = 214452854)
- @Test
- fun entireScreenCovered_shellTransit() {
- assumeTrue(isShellTransitionsEnabled)
- super.entireScreenCovered()
- }
-
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index a0892612f4e4..f5fb10611d6b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -24,9 +24,6 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import org.junit.Assume.assumeFalse
-import org.junit.Assume.assumeTrue
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -83,18 +80,9 @@ class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
/** {@inheritDoc} */
- @FlakyTest(bugId = 206753786)
+ @FlakyTest(bugId = 227430489)
@Test
override fun statusBarLayerRotatesScales() {
- // This test doesn't work in shell transitions because of b/206753786
- assumeFalse(isShellTransitionsEnabled)
- super.statusBarLayerRotatesScales()
- }
-
- @FlakyTest(bugId = 214452854)
- @Test
- fun statusBarLayerRotatesScales_shellTransit() {
- assumeTrue(isShellTransitionsEnabled)
super.statusBarLayerRotatesScales()
}
@@ -102,15 +90,6 @@ class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio
@Presubmit
@Test
override fun launcherLayerReplacesApp() {
- // This test doesn't work in shell transitions because of b/206086894
- assumeFalse(isShellTransitionsEnabled)
- super.launcherLayerReplacesApp()
- }
-
- @FlakyTest(bugId = 214452854)
- @Test
- fun launcherLayerReplacesApp_shellTransit() {
- assumeTrue(isShellTransitionsEnabled)
super.launcherLayerReplacesApp()
}
@@ -118,15 +97,6 @@ class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio
@Presubmit
@Test
override fun entireScreenCovered() {
- // This test doesn't work in shell transitions because of b/206086894
- assumeFalse(isShellTransitionsEnabled)
- super.entireScreenCovered()
- }
-
- @FlakyTest(bugId = 214452854)
- @Test
- fun entireScreenCovered_shellTransit() {
- assumeTrue(isShellTransitionsEnabled)
super.entireScreenCovered()
}
@@ -134,15 +104,6 @@ class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio
@Presubmit
@Test
override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- // This test doesn't work in shell transitions because of b/215885246
- assumeFalse(isShellTransitionsEnabled)
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
- }
-
- @FlakyTest(bugId = 214452854)
- @Test
- fun visibleLayersShownMoreThanOneConsecutiveEntry_shellTransit() {
- assumeTrue(isShellTransitionsEnabled)
super.visibleLayersShownMoreThanOneConsecutiveEntry()
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index f8348203599f..2f6b8f008119 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -24,11 +24,8 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
-import org.junit.Assume
-import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -59,11 +56,6 @@ import org.junit.runners.Parameterized
@Group1
open class OpenAppColdTest(testSpec: FlickerTestParameter)
: OpenAppFromLauncherTransition(testSpec) {
- @Before
- open fun before() {
- Assume.assumeFalse(isShellTransitionsEnabled)
- }
-
/**
* Defines the transition used to run the test
*/
@@ -121,7 +113,7 @@ open class OpenAppColdTest(testSpec: FlickerTestParameter)
override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
/** {@inheritDoc} */
- @FlakyTest(bugId = 213852103)
+ @Presubmit
@Test
override fun entireScreenCovered() = super.entireScreenCovered()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest_ShellTransit.kt
deleted file mode 100644
index 0d2869cbd178..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest_ShellTransit.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.launch
-
-import androidx.test.filters.FlakyTest
-import android.platform.test.annotations.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import org.junit.Assume
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test cold launching an app from launcher
- *
- * To run this test: `atest FlickerTests:OpenAppColdTest`
- *
- * Actions:
- * Make sure no apps are running on the device
- * Launch an app [testApp] and wait animation to complete
- *
- * Notes:
- * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
- * are inherited [OpenAppTransition]
- * 2. Part of the test setup occurs automatically via
- * [com.android.server.wm.flicker.TransitionRunnerWithRules],
- * including configuring navigation mode, initial orientation and ensuring no
- * apps are running before setup
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-@FlakyTest(bugId = 219688533)
-class OpenAppColdTest_ShellTransit(testSpec: FlickerTestParameter) : OpenAppColdTest(testSpec) {
- @Before
- override fun before() {
- Assume.assumeTrue(isShellTransitionsEnabled)
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 00fee82adf76..ee0f3d8cd945 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -135,7 +135,7 @@ open class OpenAppFromOverviewTest(testSpec: FlickerTestParameter)
override fun appLayerBecomesVisible() = super.appLayerBecomesVisible_warmStart()
/** {@inheritDoc} */
- @FlakyTest(bugId = 218624176)
+ @Presubmit
@Test
override fun appWindowBecomesVisible() = super.appWindowBecomesVisible_warmStart()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest_ShellTransit.kt
index 1c06495cf473..55e1e9ba8557 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest_ShellTransit.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest_ShellTransit.kt
@@ -54,7 +54,6 @@ import org.junit.runners.Parameterized
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group1
-@FlakyTest(bugId = 219688533)
class OpenAppFromOverviewTest_ShellTransit(testSpec: FlickerTestParameter)
: OpenAppFromOverviewTest(testSpec) {
@Before
@@ -65,6 +64,11 @@ class OpenAppFromOverviewTest_ShellTransit(testSpec: FlickerTestParameter)
/** {@inheritDoc} */
@FlakyTest(bugId = 216266712)
@Test
+ override fun appWindowBecomesTopWindow() = super.appWindowBecomesTopWindow()
+
+ /** {@inheritDoc} */
+ @FlakyTest(bugId = 216266712)
+ @Test
override fun appWindowReplacesLauncherAsTopWindow() =
super.appWindowReplacesLauncherAsTopWindow()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index f700416e4269..fbd611a37d0a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -17,7 +17,6 @@
package com.android.server.wm.flicker.launch
import androidx.test.filters.FlakyTest
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.platform.test.annotations.RequiresDevice
import android.view.Surface
@@ -99,7 +98,7 @@ open class OpenAppNonResizeableTest(testSpec: FlickerTestParameter)
* Checks that the nav bar starts the transition invisible, then becomes visible during
* the unlocking animation and remains visible at the end of the transition
*/
- @Postsubmit
+ @Presubmit
@Test
fun navBarWindowsVisibilityChanges() {
testSpec.assertWm {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 2562098a10ff..48f6aeb4d824 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -24,10 +24,7 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.helpers.setRotation
-import org.junit.Assume
-import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -59,11 +56,6 @@ import org.junit.runners.Parameterized
@Group1
open class OpenAppWarmTest(testSpec: FlickerTestParameter)
: OpenAppFromLauncherTransition(testSpec) {
- @Before
- open fun before() {
- Assume.assumeFalse(isShellTransitionsEnabled)
- }
-
/**
* Defines the transition used to run the test
*/
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest_ShellTransit.kt
deleted file mode 100644
index 3958dd2c89b4..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest_ShellTransit.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.launch
-
-import androidx.test.filters.FlakyTest
-import android.platform.test.annotations.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import org.junit.Assume
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test warm launching an app from launcher
- *
- * To run this test: `atest FlickerTests:OpenAppWarmTest`
- *
- * Actions:
- * Launch [testApp]
- * Press home
- * Relaunch an app [testApp] and wait animation to complete (only this action is traced)
- *
- * Notes:
- * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
- * are inherited [OpenAppTransition]
- * 2. Part of the test setup occurs automatically via
- * [com.android.server.wm.flicker.TransitionRunnerWithRules],
- * including configuring navigation mode, initial orientation and ensuring no
- * apps are running before setup
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-@FlakyTest(bugId = 219688533)
-class OpenAppWarmTest_ShellTransit(testSpec: FlickerTestParameter)
- : OpenAppWarmTest(testSpec) {
- @Before
- override fun before() {
- Assume.assumeTrue(isShellTransitionsEnabled)
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
index 48b8779db112..1eb3d8da9f1e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -33,15 +33,12 @@ import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
-import org.junit.Assume
-import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -73,11 +70,6 @@ open class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestPa
private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
- @Before
- open fun before() {
- Assume.assumeFalse(isShellTransitionsEnabled)
- }
-
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
@@ -97,7 +89,6 @@ open class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestPa
transitions {
taplInstrumentation.launchedAppState.quickSwitchToPreviousApp()
wmHelper.waitForFullScreenApp(testApp1.component)
- wmHelper.waitSnapshotGone()
wmHelper.waitForAppTransitionIdle()
wmHelper.waitForNavBarStatusBarVisible()
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt
deleted file mode 100644
index cffed81f6cb9..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.quickswitch
-
-import androidx.test.filters.FlakyTest
-import android.platform.test.annotations.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import org.junit.Assume
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test quick switching back to previous app from last opened app
- *
- * To run this test: `atest FlickerTests:QuickSwitchBetweenTwoAppsBackTest`
- *
- * Actions:
- * Launch an app [testApp1]
- * Launch another app [testApp2]
- * Swipe right from the bottom of the screen to quick switch back to the first app [testApp1]
- *
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-@FlakyTest(bugId = 219690120)
-class QuickSwitchBetweenTwoAppsBackTest_ShellTransit(testSpec: FlickerTestParameter)
- : QuickSwitchBetweenTwoAppsBackTest(testSpec) {
- @Before
- override fun before() {
- Assume.assumeTrue(isShellTransitionsEnabled)
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index d6c8f4601437..5474a42ccf52 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -32,7 +32,6 @@ import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
@@ -40,8 +39,6 @@ import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
import com.android.server.wm.traces.common.Rect
-import org.junit.Assume
-import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -101,7 +98,6 @@ open class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTes
taplInstrumentation.launchedAppState.quickSwitchToPreviousAppSwipeLeft()
wmHelper.waitForFullScreenApp(testApp2.component)
- wmHelper.waitSnapshotGone()
wmHelper.waitForAppTransitionIdle()
wmHelper.waitForNavBarStatusBarVisible()
}
@@ -115,12 +111,6 @@ open class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTes
}
}
- @Before
- open fun setup() {
- // This test doesn't work in shell transitions because of b/213867585
- Assume.assumeFalse(isShellTransitionsEnabled)
- }
-
/**
* Checks that the transition starts with [testApp1]'s windows filling/covering exactly the
* entirety of the display.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestShellTransit.kt
deleted file mode 100644
index 49b973390e7c..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestShellTransit.kt
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.quickswitch
-
-import android.platform.test.annotations.RequiresDevice
-import androidx.test.filters.FlakyTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import org.junit.Assume
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test quick switching back to previous app from last opened app
- *
- * To run this test: `atest FlickerTests:QuickSwitchBetweenTwoAppsForwardTestShellTransit`
- *
- * Actions:
- * Launch an app [testApp1]
- * Launch another app [testApp2]
- * Swipe right from the bottom of the screen to quick switch back to the first app [testApp1]
- * Swipe left from the bottom of the screen to quick switch forward to the second app [testApp2]
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
-class QuickSwitchBetweenTwoAppsForwardTestShellTransit(private val testSpec: FlickerTestParameter)
- : QuickSwitchBetweenTwoAppsForwardTest(testSpec) {
-
- @Before
- override fun setup() {
- // This test class should be removed after b/213867585 is fixed.
- Assume.assumeTrue(isShellTransitionsEnabled)
- }
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun startsWithApp1WindowsCoverFullScreen() =
- super.startsWithApp1WindowsCoverFullScreen()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun startsWithApp1LayersCoverFullScreen() = super.startsWithApp1LayersCoverFullScreen()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun startsWithApp1WindowBeingOnTop() = super.startsWithApp1WindowBeingOnTop()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun endsWithApp2WindowsCoveringFullScreen() =
- super.endsWithApp2WindowsCoveringFullScreen()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun endsWithApp2LayersCoveringFullScreen() =
- super.endsWithApp2LayersCoveringFullScreen()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun endsWithApp2BeingOnTop() = super.endsWithApp2BeingOnTop()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun app2WindowBecomesAndStaysVisible() = super.app2WindowBecomesAndStaysVisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun app2LayerBecomesAndStaysVisible() = super.app2LayerBecomesAndStaysVisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun app1WindowBecomesAndStaysInvisible() = super.app1WindowBecomesAndStaysInvisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun app1LayerBecomesAndStaysInvisible() = super.app1LayerBecomesAndStaysInvisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun app2WindowIsVisibleOnceApp1WindowIsInvisible() =
- super.app2WindowIsVisibleOnceApp1WindowIsInvisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun app2LayerIsVisibleOnceApp1LayerIsInvisible() =
- super.app2LayerIsVisibleOnceApp1LayerIsInvisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun navBarLayerAlwaysIsVisible() = super.navBarLayerAlwaysIsVisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun navbarIsAlwaysInRightPosition() = super.navbarIsAlwaysInRightPosition()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 214452854)
- @Test
- override fun statusBarLayerIsAlwaysVisible() = super.statusBarLayerIsAlwaysVisible()
-} \ No newline at end of file
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index b67395735426..5f606e1dab0c 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -174,7 +174,7 @@ public class TelephonySubscriptionTrackerTest {
private IntentFilter getIntentFilter() {
final ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
- verify(mContext).registerReceiver(any(), captor.capture(), any(), any(), anyInt());
+ verify(mContext).registerReceiver(any(), captor.capture(), any(), any());
return captor.getValue();
}
@@ -258,8 +258,7 @@ public class TelephonySubscriptionTrackerTest {
eq(mTelephonySubscriptionTracker),
any(IntentFilter.class),
any(),
- eq(mHandler),
- eq(Context.RECEIVER_NOT_EXPORTED));
+ eq(mHandler));
final IntentFilter filter = getIntentFilter();
assertEquals(2, filter.countActions());
assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED));